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 }