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 groovy.lang.Binding;
16  import groovy.lang.Script;
17  
18  import java.beans.PropertyChangeEvent;
19  import java.beans.PropertyChangeListener;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import javax.servlet.http.HttpServletResponse;
24  
25  import org.apache.xmlbeans.XmlException;
26  import org.apache.xmlbeans.XmlObject;
27  
28  import com.eviware.soapui.SoapUI;
29  import com.eviware.soapui.config.DispatchStyleConfig;
30  import com.eviware.soapui.config.MockOperationConfig;
31  import com.eviware.soapui.config.MockResponseConfig;
32  import com.eviware.soapui.config.DispatchStyleConfig.Enum;
33  import com.eviware.soapui.impl.actions.ShowDesktopPanelAction;
34  import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
35  import com.eviware.soapui.impl.wsdl.WsdlOperation;
36  import com.eviware.soapui.impl.wsdl.actions.mockoperation.NewMockResponseAction;
37  import com.eviware.soapui.impl.wsdl.actions.mockoperation.RemoveMockOperationAction;
38  import com.eviware.soapui.impl.wsdl.actions.mockoperation.RenameMockOperationAction;
39  import com.eviware.soapui.impl.wsdl.actions.support.ShowOnlineHelpAction;
40  import com.eviware.soapui.impl.wsdl.panels.mockoperation.actions.OpenRequestForMockOperationAction;
41  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
42  import com.eviware.soapui.model.iface.Interface;
43  import com.eviware.soapui.model.mock.MockOperation;
44  import com.eviware.soapui.model.mock.MockResponse;
45  import com.eviware.soapui.model.mock.MockRunContext;
46  import com.eviware.soapui.settings.WsdlSettings;
47  import com.eviware.soapui.support.action.ActionSupport;
48  import com.eviware.soapui.support.xml.XmlUtils;
49  
50  public class WsdlMockOperation extends AbstractWsdlModelItem<MockOperationConfig> implements MockOperation, PropertyChangeListener
51  {
52  	public final static String DISPATCH_STYLE_PROPERTY = WsdlMockOperation.class.getName() + "@dispatchstyle";
53  	public final static String DEFAULT_RESPONSE_PROPERTY = WsdlMockOperation.class.getName() + "@defaultresponse";
54  	public final static String DISPATCH_PATH_PROPERTY = WsdlMockOperation.class.getName() + "@dispatchpath";
55  	
56  	private WsdlOperation operation;
57  	private List<WsdlMockResponse> responses = new ArrayList<WsdlMockResponse>();
58  	private int currentDispatchIndex;
59  	
60  	public WsdlMockOperation(WsdlMockService mockService, MockOperationConfig config)
61     {
62     	super( config, mockService, "/mockOperation.gif" );
63     	
64     	Interface iface = mockService.getProject().getInterfaceByName( config.getInterface() );
65     	operation = ( WsdlOperation ) iface.getOperationByName( config.getOperation() );
66     	
67     	List<MockResponseConfig> responseConfigs = config.getResponseList();
68     	for( MockResponseConfig responseConfig : responseConfigs )
69     	{
70     		WsdlMockResponse wsdlMockResponse = new WsdlMockResponse( this, responseConfig );
71     		wsdlMockResponse.addPropertyChangeListener( this );
72  			responses.add( wsdlMockResponse );
73     	}
74     	
75     	initData( config );
76     	
77     	addActions();
78     }
79  
80  	private void initData( MockOperationConfig config )
81  	{
82  		if( !config.isSetName() )
83     		config.setName( operation.getName() );
84     	
85     	if( !config.isSetDispatchStyle())
86     		config.setDispatchStyle( DispatchStyleConfig.SEQUENCE );
87     	
88     	if( !config.isSetDefaultResponse() && responses.size() > 0 )
89     		setDefaultResponse( responses.get( 0 ).getName() );
90  	}
91  	
92  	private void addActions()
93  	{
94  		addAction( new ShowDesktopPanelAction( "Open MockOperation Editor", 
95           		"Opens the MockOperation Editor for this MockOperation", this ));
96  		addAction( ActionSupport.SEPARATOR_ACTION );
97  		addAction( new OpenRequestForMockOperationAction( this));
98        addAction( ActionSupport.SEPARATOR_ACTION );
99        addAction( new NewMockResponseAction( this ));
100       addAction( new RenameMockOperationAction( this ) );
101       addAction( new RemoveMockOperationAction( this ) );
102       addAction( ActionSupport.SEPARATOR_ACTION );
103       addAction( new ShowOnlineHelpAction( HelpUrls.MOCKOPERATION_HELP_URL ));
104 	}
105 	
106 	public WsdlMockOperation( WsdlMockService mockService, MockOperationConfig config, WsdlOperation operation )
107 	{
108 		super( config, mockService, "/mockOperation.gif" );
109 		this.operation = operation;
110 		
111 		config.setInterface( operation.getInterface().getName() );
112 		config.setOperation( operation.getName() );
113 		
114 		initData( config );
115 		addActions();
116 	}
117 
118 	public WsdlMockService getMockService()
119 	{
120 		return ( WsdlMockService ) getParent();
121 	}
122 
123 	public WsdlMockResponse getMockResponseAt( int index )
124 	{
125 		return responses.get( index );
126 	}
127 
128 	public WsdlOperation getOperation()
129 	{
130 		return operation;
131 	}
132 
133 	public WsdlMockResponse getMockResponseByName( String name )
134 	{
135 		return ( WsdlMockResponse ) getWsdlModelItemByName( responses, name );
136 	}
137 
138 	public int getMockResponseCount()
139 	{
140 		return responses.size();
141 	}
142 
143 	public WsdlMockResponse addNewMockResponse( MockResponseConfig responseConfig )
144 	{
145 		WsdlMockResponse mockResponse = new WsdlMockResponse( this, responseConfig );
146 		
147 		responses.add( mockResponse );
148 		if( responses.size() == 1 )
149 			setDefaultResponse( mockResponse.getName() );
150 		
151 		((WsdlMockService)getMockService()).fireMockResponseAdded( mockResponse );
152 		
153 		return mockResponse;
154 	}
155 	
156 	public WsdlMockResponse addNewMockResponse( String name, boolean createResponse )
157 	{
158 		MockResponseConfig responseConfig = getConfig().addNewResponse();
159 		responseConfig.setName( name );
160 		
161 		if( createResponse && getOperation() != null )
162 		{
163 			boolean createOptional = SoapUI.getSettings().getBoolean( WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS );
164 			responseConfig.setResponseContent( getOperation().createResponse( createOptional ));
165 		}
166 		
167 		return addNewMockResponse( responseConfig );
168 	}
169 	
170 	public void removeMockResponse( WsdlMockResponse mockResponse )
171    {
172       int ix = responses.indexOf( mockResponse );
173       responses.remove( ix );
174       mockResponse.removePropertyChangeListener( this );
175       
176       try
177       {
178       	((WsdlMockService)getMockService()).fireMockResponseRemoved( mockResponse );
179       }
180       finally
181       {
182 	      mockResponse.release();
183 	      getConfig().removeResponse( ix );
184       }
185    }
186 
187 	public WsdlMockResult dispatchRequest( WsdlMockRequest request, HttpServletResponse response ) throws DispatchException
188 	{
189 		try
190 		{
191 			WsdlMockResult result = new WsdlMockResult( request, response );
192 			
193 			if( getMockResponseCount() == 0 )
194 				throw new DispatchException( "Missing MockResponse(s) in MockOperation [" + getName() + "]" );
195 			
196 			if( getDispatchStyle() == DispatchStyleConfig.XPATH )
197 			{
198 				XmlObject[] items = evaluateDispatchXPath( request );
199 				for( XmlObject item : items )
200 				{
201 					WsdlMockResponse mockResponse = getMockResponseByName( XmlUtils.getNodeValue( item.getDomNode() ));
202 					
203 					if( mockResponse == null )
204 						mockResponse = getMockResponseByName( getDefaultResponse() );
205 					
206 					if( mockResponse != null )
207 					{
208 						result.setMockResponse( mockResponse );
209 						mockResponse.execute( request, result );
210 						
211 						return result;
212 					}
213 				}
214 				
215 				throw new DispatchException( "Missing matching response message" );
216 			}
217 			else if( getDispatchStyle() == DispatchStyleConfig.SCRIPT )
218 			{
219 				Object retVal = evaluateDispatchScript( request );
220 				
221 				WsdlMockResponse mockResponse = retVal == null ? getMockResponseByName( getDefaultResponse() ) 
222 							: getMockResponseByName( retVal.toString() );
223 				
224 				if( mockResponse != null )
225 				{
226 					result.setMockResponse( mockResponse );
227 					mockResponse.execute( request, result );
228 					
229 					return result;
230 				}
231 				else
232 				{
233 					throw new DispatchException( "Missing matching response message [" + retVal + "]" );
234 				}
235 			}
236 			else 
237 			{
238 				WsdlMockResponse mockResponse = null;
239 				synchronized( this )
240 				{
241 					if( getDispatchStyle() == DispatchStyleConfig.RANDOM )
242 					{
243 						currentDispatchIndex = ( int ) ( (Math.random() * getMockResponseCount()) + 0.5F );
244 					}
245 	
246 					if( currentDispatchIndex >= getMockResponseCount() ) 
247 						currentDispatchIndex = 0;
248 	
249 					mockResponse = getMockResponseAt( currentDispatchIndex );
250 					result.setMockResponse( mockResponse );
251 					
252 					currentDispatchIndex++;
253 				}
254 
255 				mockResponse.execute( request, result );
256 			}
257 			
258 			return result;
259 		}
260 		catch( Exception e )
261 		{
262 			throw new DispatchException( e );
263 		}
264 	}
265 
266 	public XmlObject[] evaluateDispatchXPath( WsdlMockRequest request ) throws XmlException
267 	{
268 		XmlObject xmlObject = request.getRequestXmlObject();
269 		XmlObject[] items = xmlObject.selectPath( getDispatchPath() );
270 		return items;
271 	}
272 
273 	public Object evaluateDispatchScript( WsdlMockRequest request ) throws DispatchException
274 	{
275 		String dispatchPath = getDispatchPath();
276 		if( dispatchPath == null || dispatchPath.trim().length() == 0 )
277 		{
278 			throw new DispatchException( "Dispatch Script is empty" );
279 		}
280 		
281 		try
282 		{
283 			WsdlMockService mockService = getMockService();
284 			WsdlMockRunner mockRunner = mockService.getMockRunner();
285 			MockRunContext context = mockRunner == null ? new WsdlMockRunContext( mockService ) : mockRunner.getMockContext(); 
286 			
287 			Binding localBinding = new Binding();
288 			localBinding.setVariable( "context", context );
289 			localBinding.setVariable( "mockRequest", request);
290 			localBinding.setVariable( "mockOperation", this );
291 			localBinding.setVariable( "log", SoapUI.ensureGroovyLog() );
292 			
293 			Script localScript = getMockService().getScriptShell().parse( dispatchPath );
294 			localScript.setBinding( localBinding );
295 			Object retVal = localScript.run();
296 			return retVal;
297 		}
298 		catch( Throwable e )
299 		{
300 			e.printStackTrace();
301 			throw new DispatchException( "Failed to dispatch using script; " + e );
302 		}
303 	}
304 	
305 	public DispatchStyleConfig.Enum getDispatchStyle()
306 	{
307 		return getConfig().getDispatchStyle();
308 	}
309 	
310 	public void setDispatchStyle( DispatchStyleConfig.Enum dispatchStyle )
311 	{
312 		Enum old = getDispatchStyle();
313 		getConfig().setDispatchStyle( dispatchStyle );
314 		notifyPropertyChanged( DISPATCH_STYLE_PROPERTY, old, dispatchStyle );
315 	}
316 	
317 	public String getDispatchPath()
318 	{
319 		return getConfig().getDispatchPath();
320 	}
321 	
322 	public void setDispatchPath( String dispatchPath )
323 	{
324 		String old = getDispatchPath();
325 		getConfig().setDispatchPath( dispatchPath );
326 		notifyPropertyChanged( DISPATCH_PATH_PROPERTY, old, dispatchPath );
327 	}
328 	
329 	public String getWsdlOperationName()
330 	{
331 		return operation == null ? null : operation.getName();
332 	}
333 
334 	public String getDefaultResponse()
335 	{
336 		return getConfig().getDefaultResponse();
337 	}
338 	
339 	public void setDefaultResponse( String defaultResponse )
340 	{
341 		String old = getDefaultResponse();
342 		getConfig().setDefaultResponse( defaultResponse );
343 		notifyPropertyChanged( DEFAULT_RESPONSE_PROPERTY, old, defaultResponse );
344 	}
345 
346 	public List<MockResponse> getMockResponses()
347 	{
348 		return new ArrayList<MockResponse>( responses );
349 	}
350 
351 	public void propertyChange( PropertyChangeEvent arg0 )
352 	{
353 		if( arg0.getPropertyName().equals( WsdlMockResponse.NAME_PROPERTY ))
354 		{
355 			if( arg0.getOldValue().equals( getDefaultResponse() ))
356 				setDefaultResponse( arg0.getNewValue().toString() );
357 		}
358 	}
359 	
360 	public WsdlMockResult getLastMockResult()
361 	{
362 		WsdlMockResult result = null;
363 		
364 		for( WsdlMockResponse response : responses )
365 		{
366 			WsdlMockResult mockResult = response.getMockResult();
367 			if( mockResult != null )
368 			{
369 				if( result == null || result.getTimestamp() > mockResult.getTimestamp() )
370 					result = mockResult;
371 			}
372 		}
373 		
374 		return result;
375 	}
376 
377 	public void setOperation( WsdlOperation operation )
378 	{
379 		if( operation == null )
380 		{
381 			getConfig().unsetInterface();
382 			getConfig().unsetOperation();
383 		}
384 		else
385 		{
386 			getConfig().setInterface( operation.getInterface().getName() );
387 			getConfig().setOperation( operation.getName() );
388 		}
389 		
390 		this.operation = operation;
391 	}
392 }