1
2
3
4
5
6
7
8
9
10
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 }