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.LinkedList;
17  import java.util.List;
18  
19  import javax.servlet.http.HttpServletRequest;
20  import javax.servlet.http.HttpServletResponse;
21  import javax.wsdl.BindingOperation;
22  import javax.wsdl.Part;
23  import javax.xml.namespace.QName;
24  
25  import org.apache.xmlbeans.XmlObject;
26  import org.mortbay.jetty.Request;
27  import org.w3c.dom.Element;
28  import org.w3c.dom.Node;
29  import org.w3c.dom.NodeList;
30  
31  import com.eviware.soapui.SoapUI;
32  import com.eviware.soapui.impl.wsdl.WsdlOperation;
33  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
34  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
35  import com.eviware.soapui.model.mock.MockResult;
36  import com.eviware.soapui.model.mock.MockRunListener;
37  import com.eviware.soapui.model.mock.MockRunner;
38  import com.eviware.soapui.support.xml.XmlUtils;
39  
40  public class WsdlMockRunner implements MockRunner
41  {
42  	private final WsdlMockService mockService;
43  	private List<WsdlMockResult> mockResults = Collections.synchronizedList( new LinkedList<WsdlMockResult>());
44  	private int maxResults = 100;
45  	private int removed = 0;
46  	private WsdlMockRunContext mockContext;
47  
48  	public WsdlMockRunner( WsdlMockService mockService, WsdlTestRunContext context ) throws Exception
49  	{
50  		this.mockService = mockService;
51  		
52  		mockContext = new WsdlMockRunContext( mockService, context );
53  		
54  		SoapUI.getMockEngine().startMockService( this );
55  		
56  		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
57  		
58  		for( MockRunListener listener : mockRunListeners )
59  		{
60  			listener.onMockRunnerStart( this );
61  		}
62  	}
63  
64  	public WsdlMockRunContext getMockContext()
65  	{
66  		return mockContext;
67  	}
68  
69  	public void addMockResult( WsdlMockResult mockResult )
70  	{
71  		mockResults.add( mockResult );
72  		if( mockResults.size() > maxResults )
73  		{
74  			mockResults.remove( 0 );
75  			removed++;
76  		}
77  	}
78  	
79  	public void stop()
80  	{
81  		SoapUI.getMockEngine().stopMockService( this );
82  		
83  		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
84  		
85  		for( MockRunListener listener : mockRunListeners )
86  		{
87  			listener.onMockRunnerStop( this );
88  		}
89  	}
90  
91  	public WsdlMockService getMockService()
92  	{
93  		return mockService;
94  	}
95  
96  	public WsdlMockResult dispatchRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException
97  	{
98  		WsdlMockResult result = null;
99  		MockRunListener[] mockRunListeners = mockService.getMockRunListeners();
100 		
101 		try
102 		{
103 			for( MockRunListener listener : mockRunListeners )
104 			{
105 				listener.onMockRequest( this, request, response );
106 			}
107 			
108 			long timestamp = System.currentTimeMillis();
109 			String soapAction = request.getHeader( "SOAPAction" );
110 			
111 			WsdlMockRequest mockRequest = new WsdlMockRequest( request, response, mockContext );
112 			
113 			SoapVersion soapVersion = mockRequest.getSoapVersion();
114 			if( soapVersion == null )
115 				throw new DispatchException( "Unrecognized SOAP Version" );
116 			
117 			XmlObject contentElm = mockRequest.getContentElement(); 
118 			if( contentElm == null )
119 				throw new DispatchException( "Missing content element in body" );
120 			
121 			QName contentQName = XmlUtils.getQName( contentElm.getDomNode() );
122 			NodeList contentChildNodes = null;
123 			
124 			for( int c = 0; c < mockService.getMockOperationCount(); c++ )
125 			{
126 				WsdlMockOperation mockOperation = ( WsdlMockOperation ) mockService.getMockOperationAt( c );
127 				WsdlOperation wsdlOperation = ( WsdlOperation ) mockOperation.getOperation();
128 				if( wsdlOperation == null )
129 					continue;
130 
131 				if( mockService.isRequireSoapVersion() && 
132 					 wsdlOperation.getInterface().getSoapVersion() != mockRequest.getSoapVersion() )
133 				{
134 					continue;
135 				}
136 				
137 				String action = wsdlOperation.getAction() == null ? "\"\"" : "\"" + wsdlOperation.getAction() + "\"";
138 				
139 				// matches soapAction?
140 				if( (soapAction == null && wsdlOperation.getAction() == null ) || 
141 					 (action.equals( soapAction ) || (wsdlOperation.getAction() != null && wsdlOperation.getAction().equals( soapAction ) )))
142 				{
143 					QName qname = wsdlOperation.getRequestBodyElementQName();
144 					
145 					if( !qname.equals( contentQName ))
146 						continue;
147 					
148 					long startTime = 0;
149 					
150 					// check content
151 					if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_DOCUMENT ))
152 					{
153 						// matches!
154 						startTime = System.nanoTime();
155 						result = mockOperation.dispatchRequest( mockRequest, response );
156 					}
157 					else if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_RPC ))
158 					{
159 						BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
160 						List<Part> parts = bindingOperation.getOperation().getInput().getMessage().getOrderedParts( null );
161 						
162 						if( contentChildNodes == null )
163 							contentChildNodes = XmlUtils.getChildElements( ( Element ) contentElm.getDomNode() );
164 						
165 						int i = 0;
166 						
167 						if( parts.size() > 0 )
168 						{
169 							for( ; i < contentChildNodes.getLength() && !parts.isEmpty(); i++ )
170 							{
171 								Node item = contentChildNodes.item( i );
172 								if( item.getNodeType() != Node.ELEMENT_NODE )
173 									continue;
174 								
175 								int j=0; 
176 								while ((j<parts.size()) && (!item.getNodeName().equals( parts.get( j ).getName()))) 
177 								{ 
178 									j++; 
179 								} 
180 								
181 								if (j==parts.size()) 
182 									break; 
183 								 
184 								parts.remove( j ); 
185 							}
186 						}
187 						
188 						// match?
189 						if( i == contentChildNodes.getLength() && parts.isEmpty() )
190 						{
191 							startTime = System.nanoTime();
192 							result = mockOperation.dispatchRequest( mockRequest, response );
193 						}
194 					}
195 					
196 					if( startTime == 0 )
197 					{
198 						throw new DispatchException( "Failed to find matching operation for request" );
199 					}
200 					else
201 					{
202 						((Request)request).setHandled( true );
203 						result.setTimeTaken( ( System.nanoTime() - startTime ) / 1000000 );
204 						result.setTimestamp( timestamp );
205 						addMockResult( result );
206 						return result;
207 					}
208 				}
209 			}
210 			
211 			throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element [" + 
212 						contentQName + "] with SOAP Version [" + mockRequest.getSoapVersion() + "]" );
213 		}
214 		catch( Exception e )
215 		{
216 			e.printStackTrace();
217 			
218 			if( e instanceof DispatchException )
219 				throw (DispatchException)e;
220 			
221 			throw new DispatchException( e );
222 		}
223 		finally
224 		{
225 			if( result != null )
226 			{
227 				for( MockRunListener listener : mockRunListeners )
228 				{
229 					listener.onMockResult( result );
230 				}
231 			}
232 		}
233 	}
234 
235 	public MockResult getMockResultAt( int index )
236 	{
237 		return index <= removed ? null : mockResults.get( index-removed );
238 	}
239 
240 	public int getMockResultCount()
241 	{
242 		return mockResults.size() + removed;
243 	}
244 }