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 }