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.util.Collections;
016: import java.util.HashSet;
017: import java.util.LinkedList;
018: import java.util.List;
019: import java.util.Set;
020:
021: import javax.servlet.http.HttpServletRequest;
022: import javax.servlet.http.HttpServletResponse;
023: import javax.wsdl.BindingOperation;
024: import javax.wsdl.Part;
025: import javax.xml.namespace.QName;
026:
027: import org.apache.xmlbeans.XmlObject;
028: import org.mortbay.jetty.Request;
029: import org.w3c.dom.Element;
030: import org.w3c.dom.Node;
031: import org.w3c.dom.NodeList;
032:
033: import com.eviware.soapui.SoapUI;
034: import com.eviware.soapui.impl.wsdl.WsdlInterface;
035: import com.eviware.soapui.impl.wsdl.WsdlOperation;
036: import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
037: import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
038: import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
039: import com.eviware.soapui.model.mock.MockResult;
040: import com.eviware.soapui.model.mock.MockRunListener;
041: import com.eviware.soapui.model.mock.MockRunner;
042: import com.eviware.soapui.support.xml.XmlUtils;
043:
044: /**
045: * MockRunner that dispatches Http Requests to their designated WsdlMockOperation if possible
046: *
047: * @author ole.matzura
048: */
049:
050: public class WsdlMockRunner implements MockRunner {
051: private WsdlMockService mockService;
052: private List<WsdlMockResult> mockResults = Collections
053: .synchronizedList(new LinkedList<WsdlMockResult>());
054: private long maxResults = 100;
055: private int removed = 0;
056: private WsdlMockRunContext mockContext;
057:
058: public WsdlMockRunner(WsdlMockService mockService,
059: WsdlTestRunContext context) throws Exception {
060: this .mockService = mockService;
061:
062: Set<WsdlInterface> interfaces = new HashSet<WsdlInterface>();
063:
064: for (int i = 0; i < mockService.getMockOperationCount(); i++) {
065: interfaces.add(mockService.getMockOperationAt(i)
066: .getOperation().getInterface());
067: }
068:
069: for (WsdlInterface iface : interfaces)
070: iface.getWsdlContext().loadIfNecessary(false);
071:
072: mockContext = new WsdlMockRunContext(mockService, context);
073:
074: SoapUI.getMockEngine().startMockService(this );
075:
076: MockRunListener[] mockRunListeners = mockService
077: .getMockRunListeners();
078:
079: for (MockRunListener listener : mockRunListeners) {
080: listener.onMockRunnerStart(this );
081: }
082: }
083:
084: public WsdlMockRunContext getMockContext() {
085: return mockContext;
086: }
087:
088: public synchronized void addMockResult(WsdlMockResult mockResult) {
089: mockResults.add(mockResult);
090: while (mockResults.size() > maxResults) {
091: mockResults.remove(0);
092: removed++;
093: }
094: }
095:
096: public void stop() {
097: SoapUI.getMockEngine().stopMockService(this );
098:
099: MockRunListener[] mockRunListeners = mockService
100: .getMockRunListeners();
101:
102: for (MockRunListener listener : mockRunListeners) {
103: listener.onMockRunnerStop(this );
104: }
105: }
106:
107: public WsdlMockService getMockService() {
108: return mockService;
109: }
110:
111: public long getMaxResults() {
112: return maxResults;
113: }
114:
115: public synchronized void setMaxResults(long l) {
116: this .maxResults = l;
117:
118: while (mockResults.size() > l) {
119: mockResults.remove(0);
120: removed++;
121: }
122: }
123:
124: public WsdlMockResult dispatchRequest(HttpServletRequest request,
125: HttpServletResponse response) throws DispatchException {
126: WsdlMockResult result = null;
127: MockRunListener[] mockRunListeners = mockService
128: .getMockRunListeners();
129:
130: try {
131: for (MockRunListener listener : mockRunListeners) {
132: listener.onMockRequest(this , request, response);
133: }
134:
135: long timestamp = System.currentTimeMillis();
136: String soapAction = request.getHeader("SOAPAction");
137:
138: WsdlMockRequest mockRequest = new WsdlMockRequest(request,
139: response, mockContext);
140:
141: SoapVersion soapVersion = mockRequest.getSoapVersion();
142: if (soapVersion == null)
143: throw new DispatchException("Unrecognized SOAP Version");
144:
145: XmlObject contentElm = mockRequest.getContentElement();
146: if (contentElm == null)
147: throw new DispatchException(
148: "Missing content element in body");
149:
150: QName contentQName = XmlUtils.getQName(contentElm
151: .getDomNode());
152: NodeList contentChildNodes = null;
153:
154: for (int c = 0; c < mockService.getMockOperationCount(); c++) {
155: WsdlMockOperation mockOperation = (WsdlMockOperation) mockService
156: .getMockOperationAt(c);
157: WsdlOperation wsdlOperation = (WsdlOperation) mockOperation
158: .getOperation();
159: if (wsdlOperation == null)
160: continue;
161:
162: if (mockService.isRequireSoapVersion()
163: && wsdlOperation.getInterface()
164: .getSoapVersion() != mockRequest
165: .getSoapVersion()) {
166: continue;
167: }
168:
169: String action = wsdlOperation.getAction() == null ? "\"\""
170: : "\"" + wsdlOperation.getAction() + "\"";
171:
172: // matches soapAction?
173: if ((soapAction == null && wsdlOperation.getAction() == null)
174: || (action.equals(soapAction) || (wsdlOperation
175: .getAction() != null && wsdlOperation
176: .getAction().equals(soapAction)))) {
177: QName qname = wsdlOperation
178: .getRequestBodyElementQName();
179:
180: if (!qname.equals(contentQName))
181: continue;
182:
183: long startTime = 0;
184:
185: // check content
186: if (wsdlOperation.getStyle().equals(
187: WsdlOperation.STYLE_DOCUMENT)) {
188: // matches!
189: startTime = System.nanoTime();
190: result = mockOperation.dispatchRequest(
191: mockRequest, response);
192: } else if (wsdlOperation.getStyle().equals(
193: WsdlOperation.STYLE_RPC)) {
194: BindingOperation bindingOperation = wsdlOperation
195: .getBindingOperation();
196: List<Part> parts = bindingOperation
197: .getOperation().getInput().getMessage()
198: .getOrderedParts(null);
199:
200: if (contentChildNodes == null)
201: contentChildNodes = XmlUtils
202: .getChildElements((Element) contentElm
203: .getDomNode());
204:
205: int i = 0;
206:
207: if (parts.size() > 0) {
208: for (int x = 0; x < parts.size(); x++) {
209: if (WsdlUtils.isAttachmentInputPart(
210: parts.get(x), bindingOperation)) {
211: parts.remove(x);
212: x--;
213: }
214: }
215:
216: for (; i < contentChildNodes.getLength()
217: && !parts.isEmpty(); i++) {
218: Node item = contentChildNodes.item(i);
219: if (item.getNodeType() != Node.ELEMENT_NODE)
220: continue;
221:
222: int j = 0;
223: while ((j < parts.size())
224: && (!item.getNodeName().equals(
225: parts.get(j).getName()))) {
226: j++;
227: }
228:
229: if (j == parts.size())
230: break;
231:
232: parts.remove(j);
233: }
234: }
235:
236: // match?
237: if (i == contentChildNodes.getLength()
238: && parts.isEmpty()) {
239: startTime = System.nanoTime();
240: result = mockOperation.dispatchRequest(
241: mockRequest, response);
242: }
243: }
244:
245: if (startTime == 0) {
246: throw new DispatchException(
247: "Failed to find matching operation for request");
248: } else {
249: ((Request) request).setHandled(true);
250: result
251: .setTimeTaken((System.nanoTime() - startTime) / 1000000);
252: result.setTimestamp(timestamp);
253: addMockResult(result);
254: return result;
255: }
256: }
257: }
258:
259: throw new DispatchException(
260: "Missing operation for soapAction [" + soapAction
261: + "] and body element [" + contentQName
262: + "] with SOAP Version ["
263: + mockRequest.getSoapVersion() + "]");
264: } catch (Exception e) {
265: if (e instanceof DispatchException)
266: throw (DispatchException) e;
267:
268: throw new DispatchException(e);
269: } finally {
270: if (result != null) {
271: for (MockRunListener listener : mockRunListeners) {
272: listener.onMockResult(result);
273: }
274: }
275: }
276: }
277:
278: public MockResult getMockResultAt(int index) {
279: return index <= removed ? null : mockResults.get(index
280: - removed);
281: }
282:
283: public int getMockResultCount() {
284: return mockResults.size() + removed;
285: }
286:
287: public synchronized void clearResults() {
288: mockResults.clear();
289: }
290:
291: public void release() {
292: clearResults();
293: mockService = null;
294: mockContext.clear();
295: }
296: }
|