001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.impl.wsdl.mock;
014:
015: import java.beans.PropertyChangeEvent;
016: import java.beans.PropertyChangeListener;
017: import java.util.ArrayList;
018: import java.util.List;
019:
020: import javax.servlet.http.HttpServletResponse;
021:
022: import org.apache.xmlbeans.XmlException;
023: import org.apache.xmlbeans.XmlObject;
024:
025: import com.eviware.soapui.SoapUI;
026: import com.eviware.soapui.config.DispatchStyleConfig;
027: import com.eviware.soapui.config.MockOperationConfig;
028: import com.eviware.soapui.config.MockResponseConfig;
029: import com.eviware.soapui.config.DispatchStyleConfig.Enum;
030: import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
031: import com.eviware.soapui.impl.wsdl.WsdlOperation;
032: import com.eviware.soapui.impl.wsdl.support.CompressedStringSupport;
033: import com.eviware.soapui.model.iface.Interface;
034: import com.eviware.soapui.model.mock.MockOperation;
035: import com.eviware.soapui.model.mock.MockResponse;
036: import com.eviware.soapui.model.mock.MockRunContext;
037: import com.eviware.soapui.settings.WsdlSettings;
038: import com.eviware.soapui.support.scripting.ScriptEnginePool;
039: import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
040: import com.eviware.soapui.support.xml.XmlUtils;
041:
042: /**
043: * A WsdlMockOperation in a WsdlMockService
044: *
045: * @author ole.matzura
046: */
047:
048: public class WsdlMockOperation extends
049: AbstractWsdlModelItem<MockOperationConfig> implements
050: MockOperation, PropertyChangeListener {
051: public final static String DISPATCH_STYLE_PROPERTY = WsdlMockOperation.class
052: .getName()
053: + "@dispatchstyle";
054: public final static String DEFAULT_RESPONSE_PROPERTY = WsdlMockOperation.class
055: .getName()
056: + "@defaultresponse";
057: public final static String DISPATCH_PATH_PROPERTY = WsdlMockOperation.class
058: .getName()
059: + "@dispatchpath";
060:
061: private WsdlOperation operation;
062: private List<WsdlMockResponse> responses = new ArrayList<WsdlMockResponse>();
063: private int currentDispatchIndex;
064: private ScriptEnginePool scriptEnginePool;
065:
066: public WsdlMockOperation(WsdlMockService mockService,
067: MockOperationConfig config) {
068: super (config, mockService, "/mockOperation.gif");
069:
070: Interface iface = mockService.getProject().getInterfaceByName(
071: config.getInterface());
072: operation = (WsdlOperation) iface.getOperationByName(config
073: .getOperation());
074:
075: List<MockResponseConfig> responseConfigs = config
076: .getResponseList();
077: for (MockResponseConfig responseConfig : responseConfigs) {
078: WsdlMockResponse wsdlMockResponse = new WsdlMockResponse(
079: this , responseConfig);
080: wsdlMockResponse.addPropertyChangeListener(this );
081: responses.add(wsdlMockResponse);
082: }
083:
084: initData(config);
085: }
086:
087: private void initData(MockOperationConfig config) {
088: if (!config.isSetName())
089: config.setName(operation.getName());
090:
091: if (!config.isSetDispatchStyle())
092: config.setDispatchStyle(DispatchStyleConfig.SEQUENCE);
093:
094: if (!config.isSetDefaultResponse() && responses.size() > 0)
095: setDefaultResponse(responses.get(0).getName());
096:
097: scriptEnginePool = new ScriptEnginePool(this );
098: scriptEnginePool.setScript(getDispatchPath());
099: }
100:
101: public WsdlMockOperation(WsdlMockService mockService,
102: MockOperationConfig config, WsdlOperation operation) {
103: super (config, mockService, "/mockOperation.gif");
104: this .operation = operation;
105:
106: config.setInterface(operation.getInterface().getName());
107: config.setOperation(operation.getName());
108:
109: initData(config);
110: }
111:
112: public WsdlMockService getMockService() {
113: return (WsdlMockService) getParent();
114: }
115:
116: public WsdlMockResponse getMockResponseAt(int index) {
117: return responses.get(index);
118: }
119:
120: public WsdlOperation getOperation() {
121: return operation;
122: }
123:
124: public WsdlMockResponse getMockResponseByName(String name) {
125: return (WsdlMockResponse) getWsdlModelItemByName(responses,
126: name);
127: }
128:
129: public int getMockResponseCount() {
130: return responses.size();
131: }
132:
133: public WsdlMockResponse addNewMockResponse(
134: MockResponseConfig responseConfig) {
135: WsdlMockResponse mockResponse = new WsdlMockResponse(this ,
136: responseConfig);
137:
138: responses.add(mockResponse);
139: if (responses.size() == 1)
140: setDefaultResponse(mockResponse.getName());
141:
142: ((WsdlMockService) getMockService())
143: .fireMockResponseAdded(mockResponse);
144:
145: return mockResponse;
146: }
147:
148: public WsdlMockResponse addNewMockResponse(String name,
149: boolean createResponse) {
150: MockResponseConfig responseConfig = getConfig()
151: .addNewResponse();
152: responseConfig.setName(name);
153: responseConfig.addNewResponseContent();
154:
155: if (createResponse && getOperation() != null) {
156: boolean createOptional = SoapUI
157: .getSettings()
158: .getBoolean(
159: WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS);
160: CompressedStringSupport.setString(responseConfig
161: .getResponseContent(), getOperation()
162: .createResponse(createOptional));
163: }
164:
165: return addNewMockResponse(responseConfig);
166: }
167:
168: public void removeMockResponse(WsdlMockResponse mockResponse) {
169: int ix = responses.indexOf(mockResponse);
170: responses.remove(ix);
171: mockResponse.removePropertyChangeListener(this );
172:
173: try {
174: ((WsdlMockService) getMockService())
175: .fireMockResponseRemoved(mockResponse);
176: } finally {
177: mockResponse.release();
178: getConfig().removeResponse(ix);
179: }
180: }
181:
182: public WsdlMockResult dispatchRequest(WsdlMockRequest request,
183: HttpServletResponse response) throws DispatchException {
184: try {
185: request.setOperation(getOperation());
186: WsdlMockResult result = new WsdlMockResult(request,
187: response);
188:
189: if (getMockResponseCount() == 0)
190: throw new DispatchException(
191: "Missing MockResponse(s) in MockOperation ["
192: + getName() + "]");
193:
194: if (getDispatchStyle() == DispatchStyleConfig.XPATH) {
195: XmlObject[] items = evaluateDispatchXPath(request);
196: for (XmlObject item : items) {
197: WsdlMockResponse mockResponse = getMockResponseByName(XmlUtils
198: .getNodeValue(item.getDomNode()));
199:
200: if (mockResponse == null)
201: mockResponse = getMockResponseByName(getDefaultResponse());
202:
203: if (mockResponse != null) {
204: result.setMockResponse(mockResponse);
205: mockResponse.execute(request, result);
206:
207: return result;
208: }
209: }
210:
211: throw new DispatchException(
212: "Missing matching response message");
213: } else if (getDispatchStyle() == DispatchStyleConfig.SCRIPT) {
214: Object retVal = evaluateDispatchScript(request);
215:
216: WsdlMockResponse mockResponse = retVal == null ? getMockResponseByName(getDefaultResponse())
217: : getMockResponseByName(retVal.toString());
218:
219: if (mockResponse != null) {
220: result.setMockResponse(mockResponse);
221: mockResponse.execute(request, result);
222:
223: return result;
224: } else {
225: throw new DispatchException(
226: "Missing matching response message ["
227: + retVal + "]");
228: }
229: } else {
230: WsdlMockResponse mockResponse = null;
231: synchronized (this ) {
232: if (getDispatchStyle() == DispatchStyleConfig.RANDOM) {
233: currentDispatchIndex = (int) ((Math.random() * getMockResponseCount()) + 0.5F);
234: }
235:
236: if (currentDispatchIndex >= getMockResponseCount())
237: currentDispatchIndex = 0;
238:
239: mockResponse = getMockResponseAt(currentDispatchIndex);
240: result.setMockResponse(mockResponse);
241:
242: currentDispatchIndex++;
243: }
244:
245: mockResponse.execute(request, result);
246: }
247:
248: return result;
249: } catch (Exception e) {
250: throw new DispatchException(e);
251: }
252: }
253:
254: public void release() {
255: super .release();
256:
257: for (WsdlMockResponse response : responses) {
258: response.removePropertyChangeListener(this );
259: response.release();
260: }
261:
262: scriptEnginePool.release();
263: }
264:
265: public XmlObject[] evaluateDispatchXPath(WsdlMockRequest request)
266: throws XmlException {
267: XmlObject xmlObject = request.getRequestXmlObject();
268: XmlObject[] items = xmlObject.selectPath(getDispatchPath());
269: return items;
270: }
271:
272: public Object evaluateDispatchScript(WsdlMockRequest request)
273: throws DispatchException {
274: String dispatchPath = getDispatchPath();
275: if (dispatchPath == null || dispatchPath.trim().length() == 0) {
276: throw new DispatchException("Dispatch Script is empty");
277: }
278:
279: SoapUIScriptEngine scriptEngine = scriptEnginePool
280: .getScriptEngine();
281:
282: try {
283: WsdlMockService mockService = getMockService();
284: WsdlMockRunner mockRunner = mockService.getMockRunner();
285: MockRunContext context = mockRunner == null ? new WsdlMockRunContext(
286: mockService, null)
287: : mockRunner.getMockContext();
288:
289: scriptEngine.setVariable("context", context);
290: scriptEngine.setVariable("requestContext", request
291: .getRequestContext());
292: scriptEngine.setVariable("mockRequest", request);
293: scriptEngine.setVariable("mockOperation", this );
294: scriptEngine.setVariable("log", SoapUI.ensureGroovyLog());
295:
296: scriptEngine.setScript(dispatchPath);
297: Object retVal = scriptEngine.run();
298: return retVal;
299: } catch (Throwable e) {
300: SoapUI.logError(e);
301: throw new DispatchException(
302: "Failed to dispatch using script; " + e);
303: } finally {
304: scriptEnginePool.returnScriptEngine(scriptEngine);
305: }
306: }
307:
308: public DispatchStyleConfig.Enum getDispatchStyle() {
309: return getConfig().getDispatchStyle();
310: }
311:
312: public void setDispatchStyle(DispatchStyleConfig.Enum dispatchStyle) {
313: Enum old = getDispatchStyle();
314: getConfig().setDispatchStyle(dispatchStyle);
315: notifyPropertyChanged(DISPATCH_STYLE_PROPERTY, old,
316: dispatchStyle);
317: }
318:
319: public String getDispatchPath() {
320: return getConfig().getDispatchPath();
321: }
322:
323: public void setDispatchPath(String dispatchPath) {
324: String old = getDispatchPath();
325: getConfig().setDispatchPath(dispatchPath);
326: notifyPropertyChanged(DISPATCH_PATH_PROPERTY, old, dispatchPath);
327:
328: scriptEnginePool.setScript(dispatchPath);
329: }
330:
331: public String getWsdlOperationName() {
332: return operation == null ? null : operation.getName();
333: }
334:
335: public String getDefaultResponse() {
336: return getConfig().getDefaultResponse();
337: }
338:
339: public void setDefaultResponse(String defaultResponse) {
340: String old = getDefaultResponse();
341: getConfig().setDefaultResponse(defaultResponse);
342: notifyPropertyChanged(DEFAULT_RESPONSE_PROPERTY, old,
343: defaultResponse);
344: }
345:
346: public List<MockResponse> getMockResponses() {
347: return new ArrayList<MockResponse>(responses);
348: }
349:
350: public void propertyChange(PropertyChangeEvent arg0) {
351: if (arg0.getPropertyName().equals(
352: WsdlMockResponse.NAME_PROPERTY)) {
353: if (arg0.getOldValue().equals(getDefaultResponse()))
354: setDefaultResponse(arg0.getNewValue().toString());
355: }
356: }
357:
358: public WsdlMockResult getLastMockResult() {
359: WsdlMockResult result = null;
360:
361: for (WsdlMockResponse response : responses) {
362: WsdlMockResult mockResult = response.getMockResult();
363: if (mockResult != null) {
364: if (result == null
365: || result.getTimestamp() > mockResult
366: .getTimestamp())
367: result = mockResult;
368: }
369: }
370:
371: return result;
372: }
373:
374: public void setOperation(WsdlOperation operation) {
375: if (operation == null) {
376: getConfig().unsetInterface();
377: getConfig().unsetOperation();
378: } else {
379: getConfig()
380: .setInterface(operation.getInterface().getName());
381: getConfig().setOperation(operation.getName());
382: }
383:
384: this .operation = operation;
385: }
386:
387: @Override
388: public void onSave() {
389: for (WsdlMockResponse mockResponse : responses)
390: mockResponse.onSave();
391: }
392: }
|