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.support.soap;
014:
015: import java.io.StringWriter;
016: import java.util.List;
017: import java.util.Map;
018:
019: import javax.wsdl.BindingOperation;
020: import javax.wsdl.Message;
021: import javax.wsdl.Part;
022: import javax.xml.namespace.QName;
023:
024: import org.apache.log4j.Logger;
025: import org.apache.xmlbeans.SchemaGlobalElement;
026: import org.apache.xmlbeans.SchemaType;
027: import org.apache.xmlbeans.XmlCursor;
028: import org.apache.xmlbeans.XmlObject;
029: import org.apache.xmlbeans.XmlOptions;
030: import org.w3c.dom.Document;
031: import org.w3c.dom.Node;
032:
033: import com.eviware.soapui.SoapUI;
034: import com.eviware.soapui.impl.wsdl.WsdlInterface;
035: import com.eviware.soapui.impl.wsdl.support.Constants;
036: import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext;
037: import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
038: import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils.SoapHeader;
039: import com.eviware.soapui.impl.wsdl.support.xsd.SampleXmlUtil;
040: import com.eviware.soapui.model.iface.Interface;
041: import com.eviware.soapui.model.iface.MessageBuilder;
042: import com.eviware.soapui.model.iface.Operation;
043: import com.eviware.soapui.model.iface.Request;
044: import com.eviware.soapui.model.iface.MessagePart.FaultPart;
045: import com.eviware.soapui.settings.WsdlSettings;
046: import com.eviware.soapui.support.xml.XmlUtils;
047:
048: /**
049: * Builds SOAP requests according to WSDL/XSD definitions
050: *
051: * @author Ole.Matzura
052: */
053:
054: public class SoapMessageBuilder implements MessageBuilder {
055: private final static Logger log = Logger
056: .getLogger(SoapMessageBuilder.class);
057:
058: private WsdlContext wsdlContext;
059: private WsdlInterface iface;
060:
061: public SoapMessageBuilder(WsdlInterface iface) throws Exception {
062: this .iface = iface;
063: this .wsdlContext = iface.getWsdlContext();
064: }
065:
066: public SoapMessageBuilder(WsdlContext wsdlContext) {
067: this .wsdlContext = wsdlContext;
068: }
069:
070: public Interface getInterface() {
071: return iface;
072: }
073:
074: public String buildFault(String faultcode, String faultstring) {
075: return buildFault(faultcode, faultstring, getSoapVersion());
076: }
077:
078: public SoapVersion getSoapVersion() {
079: return iface == null ? wsdlContext.getSoapVersion() : iface
080: .getSoapVersion();
081: }
082:
083: public static String buildFault(String faultcode,
084: String faultstring, SoapVersion soapVersion) {
085: SampleXmlUtil generator = new SampleXmlUtil(false);
086: generator.setTypeComment(false);
087: generator.setIgnoreOptional(true);
088:
089: String emptyResponse = buildEmptyFault(generator, soapVersion);
090:
091: if (soapVersion == SoapVersion.Soap11) {
092: emptyResponse = XmlUtils.setXPathContent(emptyResponse,
093: "//faultcode", faultcode);
094: emptyResponse = XmlUtils.setXPathContent(emptyResponse,
095: "//faultstring", faultstring);
096: } else if (soapVersion == SoapVersion.Soap12) {
097: emptyResponse = XmlUtils.setXPathContent(emptyResponse,
098: "//soap:Value", faultcode);
099: emptyResponse = XmlUtils.setXPathContent(emptyResponse,
100: "//soap:Text", faultstring);
101: emptyResponse = XmlUtils.setXPathContent(emptyResponse,
102: "//soap:Text/@xml:lang", "en");
103: }
104:
105: return emptyResponse;
106: }
107:
108: public String buildEmptyFault() {
109: return buildEmptyFault(getSoapVersion());
110: }
111:
112: public static String buildEmptyFault(SoapVersion soapVersion) {
113: SampleXmlUtil generator = new SampleXmlUtil(false);
114:
115: String emptyResponse = buildEmptyFault(generator, soapVersion);
116:
117: return emptyResponse;
118: }
119:
120: private static String buildEmptyFault(SampleXmlUtil generator,
121: SoapVersion soapVersion) {
122: String emptyResponse = buildEmptyMessage(soapVersion);
123: try {
124: XmlObject xmlObject = XmlObject.Factory
125: .parse(emptyResponse);
126: XmlCursor cursor = xmlObject.newCursor();
127:
128: if (cursor.toChild(soapVersion.getEnvelopeQName())
129: && cursor.toChild(soapVersion.getBodyQName())) {
130: SchemaType faultType = soapVersion.getFaultType();
131: Node bodyNode = cursor.getDomNode();
132: Document dom = XmlUtils.parseXml(generator
133: .createSample(faultType));
134: bodyNode.appendChild(bodyNode.getOwnerDocument()
135: .importNode(dom.getDocumentElement(), true));
136: }
137:
138: cursor.dispose();
139: emptyResponse = xmlObject.toString();
140: } catch (Exception e) {
141: SoapUI.logError(e);
142: }
143: return emptyResponse;
144: }
145:
146: public String buildEmptyMessage() {
147: return buildEmptyMessage(getSoapVersion());
148: }
149:
150: public static String buildEmptyMessage(SoapVersion soapVersion) {
151: SampleXmlUtil generator = new SampleXmlUtil(false);
152: generator.setTypeComment(false);
153: generator.setIgnoreOptional(true);
154: return generator.createSample(soapVersion.getEnvelopeType());
155: }
156:
157: public Request buildRequest(Operation operation, Map params) {
158: return null;
159: }
160:
161: public String buildSoapRequest(BindingOperation bindingOperation,
162: boolean buildOptional) throws Exception {
163: boolean inputSoapEncoded = WsdlUtils
164: .isInputSoapEncoded(bindingOperation);
165: SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
166: xmlGenerator.setIgnoreOptional(!buildOptional);
167:
168: XmlObject object = XmlObject.Factory.newInstance();
169: XmlCursor cursor = object.newCursor();
170: cursor.toNextToken();
171: cursor.beginElement(wsdlContext.getSoapVersion()
172: .getEnvelopeQName());
173:
174: if (inputSoapEncoded) {
175: cursor.insertNamespace("xsi", Constants.XSI_NS);
176: cursor.insertNamespace("xsd", Constants.XSD_NS);
177: }
178:
179: cursor.toFirstChild();
180:
181: cursor
182: .beginElement(wsdlContext.getSoapVersion()
183: .getBodyQName());
184: cursor.toFirstChild();
185:
186: if (WsdlUtils.isRpc(wsdlContext.getDefinition(),
187: bindingOperation)) {
188: buildRpcRequest(bindingOperation, cursor, xmlGenerator);
189: } else {
190: buildDocumentRequest(bindingOperation, cursor, xmlGenerator);
191: }
192:
193: addHeaders(WsdlUtils.getSoapHeaders(bindingOperation
194: .getBindingInput().getExtensibilityElements()), cursor,
195: xmlGenerator);
196: cursor.dispose();
197:
198: try {
199: StringWriter writer = new StringWriter();
200: XmlUtils.serializePretty(object, writer);
201: return writer.toString();
202: } catch (Exception e) {
203: SoapUI.logError(e);
204: return object.xmlText();
205: }
206: }
207:
208: private void addHeaders(List<SoapHeader> headers, XmlCursor cursor,
209: SampleXmlUtil xmlGenerator) throws Exception {
210: // reposition
211: cursor.toStartDoc();
212: cursor.toChild(wsdlContext.getSoapVersion().getEnvelopeQName());
213: cursor.toFirstChild();
214:
215: cursor.beginElement(wsdlContext.getSoapVersion()
216: .getHeaderQName());
217: cursor.toFirstChild();
218:
219: for (int i = 0; i < headers.size(); i++) {
220: SoapHeader header = (SoapHeader) headers.get(i);
221:
222: Message message = wsdlContext.getDefinition().getMessage(
223: header.getMessage());
224: if (message == null) {
225: log.error("Missing message for header: "
226: + header.getMessage());
227: continue;
228: }
229:
230: Part part = message.getPart(header.getPart());
231:
232: if (part != null)
233: createElementForPart(part, cursor, xmlGenerator);
234: else
235: log.error("Missing part for header; "
236: + header.getPart());
237: }
238: }
239:
240: public void createElementForPart(Part part, XmlCursor cursor,
241: SampleXmlUtil xmlGenerator) throws Exception {
242: QName elementName = part.getElementName();
243: QName typeName = part.getTypeName();
244:
245: if (elementName != null) {
246: cursor.beginElement(elementName);
247:
248: if (wsdlContext.hasSchemaTypes()) {
249: SchemaGlobalElement elm = wsdlContext
250: .getSchemaTypeLoader().findElement(elementName);
251: if (elm != null) {
252: cursor.toFirstChild();
253: xmlGenerator.createSampleForType(elm.getType(),
254: cursor);
255: } else
256: log.error("Could not find element [" + elementName
257: + "] specified in part [" + part.getName()
258: + "]");
259: }
260:
261: cursor.toParent();
262: } else {
263: cursor.beginElement(new QName(wsdlContext.getDefinition()
264: .getTargetNamespace(), part.getName()));
265: if (typeName != null && wsdlContext.hasSchemaTypes()) {
266: SchemaType type = wsdlContext.getSchemaTypeLoader()
267: .findType(typeName);
268:
269: if (type != null) {
270: cursor.toFirstChild();
271: xmlGenerator.createSampleForType(type, cursor);
272: } else
273: log.error("Could not find type [" + typeName
274: + "] specified in part [" + part.getName()
275: + "]");
276: }
277:
278: cursor.toParent();
279: }
280: }
281:
282: private void buildDocumentRequest(
283: BindingOperation bindingOperation, XmlCursor cursor,
284: SampleXmlUtil xmlGenerator) throws Exception {
285: Part[] parts = WsdlUtils.getInputParts(bindingOperation);
286:
287: for (int i = 0; i < parts.length; i++) {
288: if (!WsdlUtils.isAttachmentInputPart(parts[i],
289: bindingOperation)) {
290: XmlCursor c = cursor.newCursor();
291: c.toLastChild();
292: createElementForPart(parts[i], c, xmlGenerator);
293: c.dispose();
294: }
295: }
296: }
297:
298: private void buildDocumentResponse(
299: BindingOperation bindingOperation, XmlCursor cursor,
300: SampleXmlUtil xmlGenerator) throws Exception {
301: Part[] parts = WsdlUtils.getOutputParts(bindingOperation);
302:
303: for (int i = 0; i < parts.length; i++) {
304: if (!WsdlUtils.isAttachmentOutputPart(parts[i],
305: bindingOperation)) {
306: XmlCursor c = cursor.newCursor();
307: c.toLastChild();
308: createElementForPart(parts[i], c, xmlGenerator);
309: c.dispose();
310: }
311: }
312: }
313:
314: private void buildRpcRequest(BindingOperation bindingOperation,
315: XmlCursor cursor, SampleXmlUtil xmlGenerator)
316: throws Exception {
317: // rpc requests use the operation name as root element
318: String ns = WsdlUtils.getSoapBodyNamespace(bindingOperation
319: .getBindingInput().getExtensibilityElements());
320: if (ns == null) {
321: ns = wsdlContext.getDefinition().getTargetNamespace();
322: log
323: .warn("missing namespace on soapbind:body, using targetNamespace instead (BP violation)");
324: }
325:
326: cursor.beginElement(new QName(ns, bindingOperation.getName()));
327: if (xmlGenerator.isSoapEnc())
328: cursor.insertAttributeWithValue(new QName(wsdlContext
329: .getSoapVersion().getEnvelopeNamespace(),
330: "encodingStyle"), wsdlContext.getSoapVersion()
331: .getEncodingNamespace());
332:
333: Part[] inputParts = WsdlUtils.getInputParts(bindingOperation);
334: for (int i = 0; i < inputParts.length; i++) {
335: Part part = inputParts[i];
336: if (WsdlUtils.isAttachmentInputPart(part, bindingOperation)) {
337: if (iface.getSettings().getBoolean(
338: WsdlSettings.ATTACHMENT_PARTS)) {
339: XmlCursor c = cursor.newCursor();
340: c.toLastChild();
341: c.beginElement(part.getName());
342: c.insertAttributeWithValue("href", part.getName()
343: + "Attachment");
344: c.dispose();
345: }
346: } else {
347: if (wsdlContext.hasSchemaTypes()) {
348: QName typeName = part.getTypeName();
349: if (typeName != null) {
350: SchemaType type = wsdlContext
351: .findType(typeName);
352:
353: if (type != null) {
354: XmlCursor c = cursor.newCursor();
355: c.toLastChild();
356: c.insertElement(part.getName());
357: c.toPrevToken();
358:
359: xmlGenerator.createSampleForType(type, c);
360: c.dispose();
361: } else
362: log.warn("Failed to find type [" + typeName
363: + "]");
364: } else {
365: SchemaGlobalElement element = wsdlContext
366: .getSchemaTypeLoader().findElement(
367: part.getElementName());
368: if (element != null) {
369: XmlCursor c = cursor.newCursor();
370: c.toLastChild();
371: c.insertElement(element.getName());
372: c.toPrevToken();
373:
374: xmlGenerator.createSampleForType(element
375: .getType(), c);
376: c.dispose();
377: } else
378: log.warn("Failed to find element ["
379: + part.getElementName() + "]");
380: }
381: }
382: }
383: }
384: }
385:
386: private void buildRpcResponse(BindingOperation bindingOperation,
387: XmlCursor cursor, SampleXmlUtil xmlGenerator)
388: throws Exception {
389: // rpc requests use the operation name as root element
390: String ns = WsdlUtils.getSoapBodyNamespace(bindingOperation
391: .getBindingOutput().getExtensibilityElements());
392:
393: if (ns == null) {
394: ns = wsdlContext.getDefinition().getTargetNamespace();
395: log
396: .warn("missing namespace on soapbind:body, using targetNamespace instead (BP violation)");
397: }
398:
399: cursor.beginElement(new QName(ns, bindingOperation.getName()
400: + "Response"));
401: if (xmlGenerator.isSoapEnc())
402: cursor.insertAttributeWithValue(new QName(wsdlContext
403: .getSoapVersion().getEnvelopeNamespace(),
404: "encodingStyle"), wsdlContext.getSoapVersion()
405: .getEncodingNamespace());
406:
407: Part[] inputParts = WsdlUtils.getOutputParts(bindingOperation);
408: for (int i = 0; i < inputParts.length; i++) {
409: Part part = inputParts[i];
410: if (WsdlUtils
411: .isAttachmentOutputPart(part, bindingOperation)) {
412: if (iface.getSettings().getBoolean(
413: WsdlSettings.ATTACHMENT_PARTS)) {
414: XmlCursor c = cursor.newCursor();
415: c.toLastChild();
416: c.beginElement(part.getName());
417: c.insertAttributeWithValue("href", part.getName()
418: + "Attachment");
419: c.dispose();
420: }
421: } else {
422: if (wsdlContext.hasSchemaTypes()) {
423: QName typeName = part.getTypeName();
424: if (typeName != null) {
425: SchemaType type = wsdlContext
426: .findType(typeName);
427:
428: if (type != null) {
429: XmlCursor c = cursor.newCursor();
430: c.toLastChild();
431: c.insertElement(part.getName());
432: c.toPrevToken();
433:
434: xmlGenerator.createSampleForType(type, c);
435: c.dispose();
436: } else
437: log.warn("Failed to find type [" + typeName
438: + "]");
439: } else {
440: SchemaGlobalElement element = wsdlContext
441: .getSchemaTypeLoader().findElement(
442: part.getElementName());
443: if (element != null) {
444: XmlCursor c = cursor.newCursor();
445: c.toLastChild();
446: c.insertElement(element.getName());
447: c.toPrevToken();
448:
449: xmlGenerator.createSampleForType(element
450: .getType(), c);
451: c.dispose();
452: } else
453: log.warn("Failed to find element ["
454: + part.getElementName() + "]");
455: }
456: }
457: }
458: }
459: }
460:
461: public void setWsdlContext(WsdlContext wsdlContext) {
462: this .wsdlContext = wsdlContext;
463: }
464:
465: public void setInterface(WsdlInterface iface) {
466: this .iface = iface;
467: }
468:
469: public String buildSoapResponse(BindingOperation bindingOperation,
470: boolean buildOptional) throws Exception {
471: boolean inputSoapEncoded = WsdlUtils
472: .isInputSoapEncoded(bindingOperation);
473: SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
474: xmlGenerator.setIgnoreOptional(!buildOptional);
475:
476: XmlObject object = XmlObject.Factory.newInstance();
477: XmlCursor cursor = object.newCursor();
478: cursor.toNextToken();
479: cursor.beginElement(wsdlContext.getSoapVersion()
480: .getEnvelopeQName());
481:
482: if (inputSoapEncoded) {
483: cursor.insertNamespace("xsi", Constants.XSI_NS);
484: cursor.insertNamespace("xsd", Constants.XSD_NS);
485: }
486:
487: cursor.toFirstChild();
488:
489: cursor
490: .beginElement(wsdlContext.getSoapVersion()
491: .getBodyQName());
492: cursor.toFirstChild();
493:
494: if (WsdlUtils.isRpc(wsdlContext.getDefinition(),
495: bindingOperation)) {
496: buildRpcResponse(bindingOperation, cursor, xmlGenerator);
497: } else {
498: buildDocumentResponse(bindingOperation, cursor,
499: xmlGenerator);
500: }
501:
502: addHeaders(WsdlUtils.getSoapHeaders(bindingOperation
503: .getBindingOutput().getExtensibilityElements()),
504: cursor, xmlGenerator);
505: cursor.dispose();
506:
507: try {
508: StringWriter writer = new StringWriter();
509: XmlUtils.serializePretty(object, writer);
510: return writer.toString();
511: } catch (Exception e) {
512: SoapUI.logError(e);
513: return object.xmlText();
514: }
515: }
516:
517: public String buildFault(FaultPart faultPart) {
518: SampleXmlUtil generator = new SampleXmlUtil(false);
519: generator.setExampleContent(false);
520: generator.setTypeComment(false);
521: String faultResponse = iface.getMessageBuilder()
522: .buildEmptyFault();
523:
524: XmlCursor cursor = null;
525: try {
526: XmlObject xmlObject = XmlObject.Factory
527: .parse(faultResponse);
528: XmlObject[] detail = xmlObject.selectPath("//detail");
529: cursor = detail[0].newCursor();
530:
531: cursor.toFirstContentToken();
532:
533: generator.setTypeComment(true);
534: generator
535: .setIgnoreOptional(iface
536: .getSettings()
537: .getBoolean(
538: WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS));
539:
540: for (Part part : faultPart.getWsdlParts())
541: createElementForPart(part, cursor, generator);
542:
543: faultResponse = xmlObject
544: .xmlText(new XmlOptions()
545: .setSaveAggressiveNamespaces()
546: .setSavePrettyPrint());
547: } catch (Exception e1) {
548: SoapUI.logError(e1);
549: } finally {
550: if (cursor != null)
551: cursor.dispose();
552: }
553:
554: return faultResponse;
555: }
556: }
|