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 e.printStackTrace();
263 throw new DispatchException( e );
264 }
265 }
266
267 public void release()
268 {
269 super.release();
270
271 for( WsdlMockResponse response : responses )
272 {
273 response.removePropertyChangeListener( this );
274 response.release();
275 }
276 }
277
278 public XmlObject[] evaluateDispatchXPath( WsdlMockRequest request ) throws XmlException
279 {
280 XmlObject xmlObject = request.getRequestXmlObject();
281 XmlObject[] items = xmlObject.selectPath( getDispatchPath() );
282 return items;
283 }
284
285 public Object evaluateDispatchScript( WsdlMockRequest request ) throws DispatchException
286 {
287 String dispatchPath = getDispatchPath();
288 if( dispatchPath == null || dispatchPath.trim().length() == 0 )
289 {
290 throw new DispatchException( "Dispatch Script is empty" );
291 }
292
293 try
294 {
295 WsdlMockService mockService = getMockService();
296 WsdlMockRunner mockRunner = mockService.getMockRunner();
297 MockRunContext context = mockRunner == null ? new WsdlMockRunContext( mockService, null ) : mockRunner.getMockContext();
298
299 Binding localBinding = new Binding();
300 localBinding.setVariable( "context", context );
301 localBinding.setVariable( "mockRequest", request);
302 localBinding.setVariable( "mockOperation", this );
303 localBinding.setVariable( "log", SoapUI.ensureGroovyLog() );
304
305 Script localScript = getMockService().getScriptShell().parse( dispatchPath );
306 localScript.setBinding( localBinding );
307 Object retVal = localScript.run();
308 return retVal;
309 }
310 catch( Throwable e )
311 {
312 e.printStackTrace();
313 throw new DispatchException( "Failed to dispatch using script; " + e );
314 }
315 }
316
317 public DispatchStyleConfig.Enum getDispatchStyle()
318 {
319 return getConfig().getDispatchStyle();
320 }
321
322 public void setDispatchStyle( DispatchStyleConfig.Enum dispatchStyle )
323 {
324 Enum old = getDispatchStyle();
325 getConfig().setDispatchStyle( dispatchStyle );
326 notifyPropertyChanged( DISPATCH_STYLE_PROPERTY, old, dispatchStyle );
327 }
328
329 public String getDispatchPath()
330 {
331 return getConfig().getDispatchPath();
332 }
333
334 public void setDispatchPath( String dispatchPath )
335 {
336 String old = getDispatchPath();
337 getConfig().setDispatchPath( dispatchPath );
338 notifyPropertyChanged( DISPATCH_PATH_PROPERTY, old, dispatchPath );
339 }
340
341 public String getWsdlOperationName()
342 {
343 return operation == null ? null : operation.getName();
344 }
345
346 public String getDefaultResponse()
347 {
348 return getConfig().getDefaultResponse();
349 }
350
351 public void setDefaultResponse( String defaultResponse )
352 {
353 String old = getDefaultResponse();
354 getConfig().setDefaultResponse( defaultResponse );
355 notifyPropertyChanged( DEFAULT_RESPONSE_PROPERTY, old, defaultResponse );
356 }
357
358 public List<MockResponse> getMockResponses()
359 {
360 return new ArrayList<MockResponse>( responses );
361 }
362
363 public void propertyChange( PropertyChangeEvent arg0 )
364 {
365 if( arg0.getPropertyName().equals( WsdlMockResponse.NAME_PROPERTY ))
366 {
367 if( arg0.getOldValue().equals( getDefaultResponse() ))
368 setDefaultResponse( arg0.getNewValue().toString() );
369 }
370 }
371
372 public WsdlMockResult getLastMockResult()
373 {
374 WsdlMockResult result = null;
375
376 for( WsdlMockResponse response : responses )
377 {
378 WsdlMockResult mockResult = response.getMockResult();
379 if( mockResult != null )
380 {
381 if( result == null || result.getTimestamp() > mockResult.getTimestamp() )
382 result = mockResult;
383 }
384 }
385
386 return result;
387 }
388
389 public void setOperation( WsdlOperation operation )
390 {
391 if( operation == null )
392 {
393 getConfig().unsetInterface();
394 getConfig().unsetOperation();
395 }
396 else
397 {
398 getConfig().setInterface( operation.getInterface().getName() );
399 getConfig().setOperation( operation.getName() );
400 }
401
402 this.operation = operation;
403 }
404 }