View Javadoc

    1   /*
    2    *  soapUI, copyright (C) 2004-2007 eviware.com
    3    *
    4    *  soapUI is free software; you can redistribute it and/or modify it under the
    5    *  terms of version 2.1 of the GNU Lesser General Public License as published by
    6    *  the Free Software Foundation.
    7    *
    8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
    9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    10   *  See the GNU Lesser General Public License for more details at gnu.org.
    11   */
    12
    13  package com.eviware.soapui.impl.wsdl.mock;
    14
    15  import java.util.Collections;
    16  import java.util.HashSet;
    17  import java.util.LinkedList;
    18  import java.util.List;
    19  import java.util.Set;
    20
    21  import javax.servlet.http.HttpServletRequest;
    22  import javax.servlet.http.HttpServletResponse;
    23  import javax.wsdl.BindingOperation;
    24  import javax.wsdl.Part;
    25  import javax.xml.namespace.QName;
    26
    27  import org.apache.xmlbeans.XmlObject;
    28  import org.mortbay.jetty.Request;
    29  import org.w3c.dom.Element;
    30  import org.w3c.dom.Node;
    31  import org.w3c.dom.NodeList;
    32
    33  import com.eviware.soapui.SoapUI;
    34  import com.eviware.soapui.impl.wsdl.WsdlInterface;
    35  import com.eviware.soapui.impl.wsdl.WsdlOperation;
    36  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
    37  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
    38  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
    39  import com.eviware.soapui.model.mock.MockResult;
    40  import com.eviware.soapui.model.mock.MockRunListener;
    41  import com.eviware.soapui.model.mock.MockRunner;
    42  import com.eviware.soapui.support.xml.XmlUtils;
    43
    44  /***
    45   * MockRunner that dispatches Http Requests to their designated WsdlMockOperation if possible
    46   *
    47   * @author ole.matzura
    48   */
    49
    50  public class WsdlMockRunner implements MockRunner
    51  {
    52  	private WsdlMockService mockService;
    53  	private List<WsdlMockResult> mockResults = Collections.synchronizedList( new LinkedList<WsdlMockResult>());
    54  	private long maxResults = 100;
    55  	private int removed = 0;
    56  	private WsdlMockRunContext mockContext;
    57
    58  	public WsdlMockRunner( WsdlMockService mockService, WsdlTestRunContext context ) throws Exception
    59  	{
    60  		this.mockService = mockService;
    61
    62  		Set<WsdlInterface> interfaces = new HashSet<WsdlInterface>();
    63
    64  		for( int i = 0; i < mockService.getMockOperationCount(); i++ )
    65  		{
    66  			WsdlOperation operation = mockService.getMockOperationAt( i ).getOperation();
    67  			if( operation != null )
    68  				interfaces.add( operation.getInterface() );
    69  		}
    70
    71  		for( WsdlInterface iface : interfaces )
    72  			iface.getWsdlContext().loadIfNecessary( false );
    73
    74  		mockContext = new WsdlMockRunContext( mockService, context );
    75
    76  		SoapUI.getMockEngine().startMockService( this );
    77
    78  		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
    79
    80  		for( MockRunListener listener : mockRunListeners )
    81  		{
    82  			listener.onMockRunnerStart( this );
    83  		}
    84  	}
    85
    86  	public WsdlMockRunContext getMockContext()
    87  	{
    88  		return mockContext;
    89  	}
    90
    91  	public synchronized void addMockResult( WsdlMockResult mockResult )
    92  	{
    93  		mockResults.add( mockResult );
    94  		while( mockResults.size() > maxResults )
    95  		{
    96  			mockResults.remove( 0 );
    97  			removed++;
    98  		}
    99  	}
    100
    101 	public void stop()
    102 	{
    103 		SoapUI.getMockEngine().stopMockService( this );
    104
    105 		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
    106
    107 		for( MockRunListener listener : mockRunListeners )
    108 		{
    109 			listener.onMockRunnerStop( this );
    110 		}
    111 	}
    112
    113 	public WsdlMockService getMockService()
    114 	{
    115 		return mockService;
    116 	}
    117
    118 	public long getMaxResults()
    119 	{
    120 		return maxResults;
    121 	}
    122
    123 	public synchronized void setMaxResults( long l )
    124 	{
    125 		this.maxResults = l;
    126
    127 		while( mockResults.size() > l )
    128 		{
    129 			mockResults.remove( 0 );
    130 			removed++;
    131 		}
    132 	}
    133
    134 	@SuppressWarnings("unchecked")
    135 	public WsdlMockResult dispatchRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
    136 	{
    137 		WsdlMockResult result = null;
    138 		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
    139
    140 		try
    141 		{
    142 			for( MockRunListener listener : mockRunListeners )
    143 			{
    144 				listener.onMockRequest( this, request, response );
    145 			}
    146
    147 			long timestamp = System.currentTimeMillis();
    148 			String soapAction = request.getHeader( "SOAPAction" );
    149
    150 			WsdlMockRequest mockRequest = new WsdlMockRequest( request, response, mockContext );
    151
    152 			SoapVersion soapVersion = mockRequest.getSoapVersion();
    153 			if( soapVersion == null )
    154 				throw new DispatchException( "Unrecognized SOAP Version" );
    155
    156 			XmlObject contentElm = mockRequest.getContentElement();
    157 			if( contentElm == null )
    158 				throw new DispatchException( "Missing content element in body" );
    159
    160 			QName contentQName = XmlUtils.getQName( contentElm.getDomNode() );
    161 			NodeList contentChildNodes = null;
    162
    163 			for( int c = 0; c < mockService.getMockOperationCount(); c++ )
    164 			{
    165 				WsdlMockOperation mockOperation = ( WsdlMockOperation ) mockService.getMockOperationAt( c );
    166 				WsdlOperation wsdlOperation = ( WsdlOperation ) mockOperation.getOperation();
    167 				if( wsdlOperation == null )
    168 					continue;
    169
    170 				if( mockService.isRequireSoapVersion() &&
    171 					 wsdlOperation.getInterface().getSoapVersion() != mockRequest.getSoapVersion() )
    172 				{
    173 					continue;
    174 				}
    175
    176 				String action = wsdlOperation.getAction() == null ? "\"\"" : "\"" + wsdlOperation.getAction() + "\"";
    177
    178 				// matches soapAction?
    179 				if( (soapAction == null && wsdlOperation.getAction() == null ) ||
    180 					 (action.equals( soapAction ) || (wsdlOperation.getAction() != null && wsdlOperation.getAction().equals( soapAction ) )))
    181 				{
    182 					QName qname = wsdlOperation.getRequestBodyElementQName();
    183
    184 					if( !qname.equals( contentQName ))
    185 						continue;
    186
    187 					long startTime = 0;
    188
    189 					// check content
    190 					if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_DOCUMENT ))
    191 					{
    192 						// matches!
    193 						startTime = System.nanoTime();
    194 						result = mockOperation.dispatchRequest( mockRequest, response );
    195 					}
    196 					else if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_RPC ))
    197 					{
    198 						BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
    199 						List<Part> parts = bindingOperation.getOperation().getInput().getMessage().getOrderedParts( null );
    200
    201 						if( contentChildNodes == null )
    202 							contentChildNodes = XmlUtils.getChildElements( ( Element ) contentElm.getDomNode() );
    203
    204 						int i = 0;
    205
    206 						if( parts.size() > 0 )
    207 						{
    208 							for( int x = 0; x < parts.size(); x++ )
    209 							{
    210 								if( WsdlUtils.isAttachmentInputPart( parts.get( x ), bindingOperation ))
    211 								{
    212 									parts.remove( x );
    213 									x--;
    214 								}
    215 							}
    216
    217 							for( ; i < contentChildNodes.getLength() && !parts.isEmpty(); i++ )
    218 							{
    219 								Node item = contentChildNodes.item( i );
    220 								if( item.getNodeType() != Node.ELEMENT_NODE )
    221 									continue;
    222
    223 								int j=0;
    224 								while ((j<parts.size()) && (!item.getNodeName().equals( parts.get( j ).getName())))
    225 								{
    226 									j++;
    227 								}
    228
    229 								if (j==parts.size())
    230 									break;
    231
    232 								parts.remove( j );
    233 							}
    234 						}
    235
    236 						// match?
    237 						if( i == contentChildNodes.getLength() && parts.isEmpty() )
    238 						{
    239 							startTime = System.nanoTime();
    240 							result = mockOperation.dispatchRequest( mockRequest, response );
    241 						}
    242 					}
    243
    244 					if( startTime == 0 )
    245 					{
    246 						throw new DispatchException( "Failed to find matching operation for request" );
    247 					}
    248 					else
    249 					{
    250 						((Request)request).setHandled( true );
    251 						result.setTimeTaken( ( System.nanoTime() - startTime ) / 1000000 );
    252 						result.setTimestamp( timestamp );
    253 						addMockResult( result );
    254 						return result;
    255 					}
    256 				}
    257 			}
    258
    259 			throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element [" +
    260 						contentQName + "] with SOAP Version [" + mockRequest.getSoapVersion() + "]" );
    261 		}
    262 		catch( Exception e )
    263 		{
    264 			if( e instanceof DispatchException )
    265 				throw (DispatchException)e;
    266
    267 			throw new DispatchException( e );
    268 		}
    269 		finally
    270 		{
    271 			if( result != null )
    272 			{
    273 				for( MockRunListener listener : mockRunListeners )
    274 				{
    275 					listener.onMockResult( result );
    276 				}
    277 			}
    278 		}
    279 	}
    280
    281 	public MockResult getMockResultAt( int index )
    282 	{
    283 		return index <= removed ? null : mockResults.get( index-removed );
    284 	}
    285
    286 	public int getMockResultCount()
    287 	{
    288 		return mockResults.size() + removed;
    289 	}
    290
    291 	public synchronized void clearResults()
    292 	{
    293 		mockResults.clear();
    294 	}
    295
    296 	public void release()
    297 	{
    298 		clearResults();
    299 		mockService = null;
    300 		mockContext.clear();
    301 	}
    302 }