View Javadoc

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