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