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  			interfaces.add(  mockService.getMockOperationAt( i ).getOperation().getInterface() );
    67  		}
    68
    69  		for( WsdlInterface iface : interfaces )
    70  			iface.getWsdlContext().loadIfNecessary( false );
    71
    72  		mockContext = new WsdlMockRunContext( mockService, context );
    73
    74  		SoapUI.getMockEngine().startMockService( this );
    75
    76  		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
    77
    78  		for( MockRunListener listener : mockRunListeners )
    79  		{
    80  			listener.onMockRunnerStart( this );
    81  		}
    82  	}
    83
    84  	public WsdlMockRunContext getMockContext()
    85  	{
    86  		return mockContext;
    87  	}
    88
    89  	public synchronized void addMockResult( WsdlMockResult mockResult )
    90  	{
    91  		mockResults.add( mockResult );
    92  		while( mockResults.size() > maxResults )
    93  		{
    94  			mockResults.remove( 0 );
    95  			removed++;
    96  		}
    97  	}
    98
    99  	public void stop()
    100 	{
    101 		SoapUI.getMockEngine().stopMockService( this );
    102
    103 		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
    104
    105 		for( MockRunListener listener : mockRunListeners )
    106 		{
    107 			listener.onMockRunnerStop( this );
    108 		}
    109 	}
    110
    111 	public WsdlMockService getMockService()
    112 	{
    113 		return mockService;
    114 	}
    115
    116 	public long getMaxResults()
    117 	{
    118 		return maxResults;
    119 	}
    120
    121 	public synchronized void setMaxResults( long l )
    122 	{
    123 		this.maxResults = l;
    124
    125 		while( mockResults.size() > l )
    126 		{
    127 			mockResults.remove( 0 );
    128 			removed++;
    129 		}
    130 	}
    131
    132 	public WsdlMockResult dispatchRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
    133 	{
    134 		WsdlMockResult result = null;
    135 		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
    136
    137 		try
    138 		{
    139 			for( MockRunListener listener : mockRunListeners )
    140 			{
    141 				listener.onMockRequest( this, request, response );
    142 			}
    143
    144 			long timestamp = System.currentTimeMillis();
    145 			String soapAction = request.getHeader( "SOAPAction" );
    146
    147 			WsdlMockRequest mockRequest = new WsdlMockRequest( request, response, mockContext );
    148
    149 			SoapVersion soapVersion = mockRequest.getSoapVersion();
    150 			if( soapVersion == null )
    151 				throw new DispatchException( "Unrecognized SOAP Version" );
    152
    153 			XmlObject contentElm = mockRequest.getContentElement();
    154 			if( contentElm == null )
    155 				throw new DispatchException( "Missing content element in body" );
    156
    157 			QName contentQName = XmlUtils.getQName( contentElm.getDomNode() );
    158 			NodeList contentChildNodes = null;
    159
    160 			for( int c = 0; c < mockService.getMockOperationCount(); c++ )
    161 			{
    162 				WsdlMockOperation mockOperation = ( WsdlMockOperation ) mockService.getMockOperationAt( c );
    163 				WsdlOperation wsdlOperation = ( WsdlOperation ) mockOperation.getOperation();
    164 				if( wsdlOperation == null )
    165 					continue;
    166
    167 				if( mockService.isRequireSoapVersion() &&
    168 					 wsdlOperation.getInterface().getSoapVersion() != mockRequest.getSoapVersion() )
    169 				{
    170 					continue;
    171 				}
    172
    173 				String action = wsdlOperation.getAction() == null ? "\"\"" : "\"" + wsdlOperation.getAction() + "\"";
    174
    175 				// matches soapAction?
    176 				if( (soapAction == null && wsdlOperation.getAction() == null ) ||
    177 					 (action.equals( soapAction ) || (wsdlOperation.getAction() != null && wsdlOperation.getAction().equals( soapAction ) )))
    178 				{
    179 					QName qname = wsdlOperation.getRequestBodyElementQName();
    180
    181 					if( !qname.equals( contentQName ))
    182 						continue;
    183
    184 					long startTime = 0;
    185
    186 					// check content
    187 					if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_DOCUMENT ))
    188 					{
    189 						// matches!
    190 						startTime = System.nanoTime();
    191 						result = mockOperation.dispatchRequest( mockRequest, response );
    192 					}
    193 					else if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_RPC ))
    194 					{
    195 						BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
    196 						List<Part> parts = bindingOperation.getOperation().getInput().getMessage().getOrderedParts( null );
    197
    198 						if( contentChildNodes == null )
    199 							contentChildNodes = XmlUtils.getChildElements( ( Element ) contentElm.getDomNode() );
    200
    201 						int i = 0;
    202
    203 						if( parts.size() > 0 )
    204 						{
    205 							for( int x = 0; x < parts.size(); x++ )
    206 							{
    207 								if( WsdlUtils.isAttachmentInputPart( parts.get( x ), bindingOperation ))
    208 								{
    209 									parts.remove( x );
    210 									x--;
    211 								}
    212 							}
    213
    214 							for( ; i < contentChildNodes.getLength() && !parts.isEmpty(); i++ )
    215 							{
    216 								Node item = contentChildNodes.item( i );
    217 								if( item.getNodeType() != Node.ELEMENT_NODE )
    218 									continue;
    219
    220 								int j=0;
    221 								while ((j<parts.size()) && (!item.getNodeName().equals( parts.get( j ).getName())))
    222 								{
    223 									j++;
    224 								}
    225
    226 								if (j==parts.size())
    227 									break;
    228
    229 								parts.remove( j );
    230 							}
    231 						}
    232
    233 						// match?
    234 						if( i == contentChildNodes.getLength() && parts.isEmpty() )
    235 						{
    236 							startTime = System.nanoTime();
    237 							result = mockOperation.dispatchRequest( mockRequest, response );
    238 						}
    239 					}
    240
    241 					if( startTime == 0 )
    242 					{
    243 						throw new DispatchException( "Failed to find matching operation for request" );
    244 					}
    245 					else
    246 					{
    247 						((Request)request).setHandled( true );
    248 						result.setTimeTaken( ( System.nanoTime() - startTime ) / 1000000 );
    249 						result.setTimestamp( timestamp );
    250 						addMockResult( result );
    251 						return result;
    252 					}
    253 				}
    254 			}
    255
    256 			throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element [" +
    257 						contentQName + "] with SOAP Version [" + mockRequest.getSoapVersion() + "]" );
    258 		}
    259 		catch( Exception e )
    260 		{
    261 			if( e instanceof DispatchException )
    262 				throw (DispatchException)e;
    263
    264 			throw new DispatchException( e );
    265 		}
    266 		finally
    267 		{
    268 			if( result != null )
    269 			{
    270 				for( MockRunListener listener : mockRunListeners )
    271 				{
    272 					listener.onMockResult( result );
    273 				}
    274 			}
    275 		}
    276 	}
    277
    278 	public MockResult getMockResultAt( int index )
    279 	{
    280 		return index <= removed ? null : mockResults.get( index-removed );
    281 	}
    282
    283 	public int getMockResultCount()
    284 	{
    285 		return mockResults.size() + removed;
    286 	}
    287
    288 	public synchronized void clearResults()
    289 	{
    290 		mockResults.clear();
    291 	}
    292
    293 	public void release()
    294 	{
    295 		clearResults();
    296 		mockService = null;
    297 		mockContext.clear();
    298 	}
    299 }