1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.impl.wsdl.support.soap;
14
15 import com.eviware.soapui.SoapUI;
16 import com.eviware.soapui.impl.wsdl.WsdlInterface;
17 import com.eviware.soapui.impl.wsdl.support.Constants;
18 import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext;
19 import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
20 import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils.SoapHeader;
21 import com.eviware.soapui.impl.wsdl.support.xsd.SampleXmlUtil;
22 import com.eviware.soapui.model.iface.Interface;
23 import com.eviware.soapui.model.iface.MessageBuilder;
24 import com.eviware.soapui.model.iface.MessagePart.FaultPart;
25 import com.eviware.soapui.settings.WsdlSettings;
26 import com.eviware.soapui.support.xml.XmlUtils;
27 import org.apache.log4j.Logger;
28 import org.apache.xmlbeans.*;
29 import org.w3c.dom.Document;
30 import org.w3c.dom.Node;
31
32 import javax.wsdl.BindingOperation;
33 import javax.wsdl.BindingOutput;
34 import javax.wsdl.Message;
35 import javax.wsdl.Part;
36 import javax.xml.namespace.QName;
37 import java.io.StringWriter;
38 import java.util.List;
39 import java.util.Map;
40
41 /***
42 * Builds SOAP requests according to WSDL/XSD definitions
43 *
44 * @author Ole.Matzura
45 */
46
47 public class SoapMessageBuilder implements MessageBuilder
48 {
49 private final static Logger log = Logger.getLogger( SoapMessageBuilder.class );
50
51 private WsdlContext wsdlContext;
52 private WsdlInterface iface;
53 private Map<QName,String[]> multiValues = null;
54
55 public SoapMessageBuilder(WsdlInterface iface) throws Exception
56 {
57 this.iface = iface;
58 this.wsdlContext = iface.getWsdlContext();
59 }
60
61 public SoapMessageBuilder(WsdlContext wsdlContext)
62 {
63 this.wsdlContext = wsdlContext;
64 }
65
66 public void setMultiValues(Map<QName,String[]> multiValues)
67 {
68 this.multiValues = multiValues;
69 }
70
71 public Interface getInterface()
72 {
73 return iface;
74 }
75
76 public String buildFault( String faultcode, String faultstring )
77 {
78 return buildFault( faultcode, faultstring, getSoapVersion() );
79 }
80
81 public SoapVersion getSoapVersion()
82 {
83 return iface == null ? wsdlContext.getSoapVersion() : iface.getSoapVersion();
84 }
85
86 public static String buildFault( String faultcode, String faultstring, SoapVersion soapVersion )
87 {
88 SampleXmlUtil generator = new SampleXmlUtil( false );
89 generator.setTypeComment( false );
90 generator.setIgnoreOptional( true );
91
92 String emptyResponse = buildEmptyFault( generator, soapVersion );
93
94 if( soapVersion == SoapVersion.Soap11 )
95 {
96 emptyResponse = XmlUtils.setXPathContent( emptyResponse, "//faultcode", faultcode );
97 emptyResponse = XmlUtils.setXPathContent( emptyResponse, "//faultstring", faultstring );
98 }
99 else if( soapVersion == SoapVersion.Soap12 )
100 {
101 emptyResponse = XmlUtils.setXPathContent( emptyResponse, "//soap:Value", faultcode );
102 emptyResponse = XmlUtils.setXPathContent( emptyResponse, "//soap:Text", faultstring );
103 emptyResponse = XmlUtils.setXPathContent( emptyResponse, "//soap:Text/@xml:lang", "en" );
104 }
105
106 return emptyResponse;
107 }
108
109 public String buildEmptyFault()
110 {
111 return buildEmptyFault( getSoapVersion() );
112 }
113
114 public static String buildEmptyFault( SoapVersion soapVersion )
115 {
116 SampleXmlUtil generator = new SampleXmlUtil( false );
117
118 String emptyResponse = buildEmptyFault( generator, soapVersion );
119
120 return emptyResponse;
121 }
122
123 private static String buildEmptyFault( SampleXmlUtil generator, SoapVersion soapVersion )
124 {
125 String emptyResponse = buildEmptyMessage( soapVersion );
126 try
127 {
128 XmlObject xmlObject = XmlObject.Factory.parse( emptyResponse );
129 XmlCursor cursor = xmlObject.newCursor();
130
131 if( cursor.toChild( soapVersion.getEnvelopeQName() ) && cursor.toChild( soapVersion.getBodyQName() ))
132 {
133 SchemaType faultType = soapVersion.getFaultType();
134 Node bodyNode = cursor.getDomNode();
135 Document dom = XmlUtils.parseXml( generator.createSample( faultType ) );
136 bodyNode.appendChild( bodyNode.getOwnerDocument().importNode( dom.getDocumentElement(), true ) );
137 }
138
139 cursor.dispose();
140 emptyResponse = xmlObject.toString();
141 }
142 catch( Exception e )
143 {
144 SoapUI.logError( e );
145 }
146 return emptyResponse;
147 }
148
149 public String buildEmptyMessage()
150 {
151 return buildEmptyMessage( getSoapVersion() );
152 }
153
154 public static String buildEmptyMessage( SoapVersion soapVersion )
155 {
156 SampleXmlUtil generator = new SampleXmlUtil( false );
157 generator.setTypeComment( false );
158 generator.setIgnoreOptional( true );
159 return generator.createSample( soapVersion.getEnvelopeType() );
160 }
161
162 public String buildSoapMessageFromInput(BindingOperation bindingOperation, boolean buildOptional ) throws Exception
163 {
164 return buildSoapMessageFromInput(bindingOperation, buildOptional, true);
165 }
166
167 public String buildSoapMessageFromInput(BindingOperation bindingOperation, boolean buildOptional,
168 boolean alwaysBuildHeaders) throws Exception
169 {
170 boolean inputSoapEncoded = WsdlUtils.isInputSoapEncoded( bindingOperation );
171 SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
172 xmlGenerator.setMultiValues(multiValues);
173 xmlGenerator.setIgnoreOptional( !buildOptional );
174
175 XmlObject object = XmlObject.Factory.newInstance();
176 XmlCursor cursor = object.newCursor();
177 cursor.toNextToken();
178 cursor.beginElement( wsdlContext.getSoapVersion().getEnvelopeQName() );
179
180 if( inputSoapEncoded )
181 {
182 cursor.insertNamespace( "xsi", Constants.XSI_NS );
183 cursor.insertNamespace( "xsd", Constants.XSD_NS );
184 }
185
186 cursor.toFirstChild();
187
188 cursor.beginElement(wsdlContext.getSoapVersion().getBodyQName());
189 cursor.toFirstChild();
190
191 if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
192 {
193 buildRpcRequest( bindingOperation, cursor, xmlGenerator );
194 }
195 else
196 {
197 buildDocumentRequest( bindingOperation, cursor, xmlGenerator );
198 }
199
200 if(alwaysBuildHeaders)
201 {
202 List extensibilityElements = bindingOperation.getBindingInput().getExtensibilityElements();
203 List<SoapHeader> soapHeaders = WsdlUtils.getSoapHeaders( extensibilityElements);
204 addHeaders( soapHeaders, cursor, xmlGenerator);
205 }
206 cursor.dispose();
207
208 try
209 {
210 StringWriter writer = new StringWriter();
211 XmlUtils.serializePretty( object, writer );
212 return writer.toString();
213 }
214 catch( Exception e )
215 {
216 SoapUI.logError( e );
217 return object.xmlText();
218 }
219 }
220
221 private void addHeaders(List<SoapHeader> headers, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
222 {
223
224 cursor.toStartDoc();
225 cursor.toChild(wsdlContext.getSoapVersion().getEnvelopeQName());
226 cursor.toFirstChild();
227
228 cursor.beginElement(wsdlContext.getSoapVersion().getHeaderQName());
229 cursor.toFirstChild();
230
231 for (int i = 0; i < headers.size(); i++)
232 {
233 SoapHeader header = headers.get(i);
234
235 Message message = wsdlContext.getDefinition().getMessage( header.getMessage() );
236 if( message == null )
237 {
238 log.error( "Missing message for header: " + header.getMessage() );
239 continue;
240 }
241
242 Part part = message.getPart( header.getPart() );
243
244 if( part != null )
245 createElementForPart( part, cursor, xmlGenerator );
246 else
247 log.error( "Missing part for header; " + header.getPart() );
248 }
249 }
250
251 public void createElementForPart(Part part, XmlCursor cursor, SampleXmlUtil xmlGenerator ) throws Exception
252 {
253 QName elementName = part.getElementName();
254 QName typeName = part.getTypeName();
255
256 if( elementName != null )
257 {
258 cursor.beginElement(elementName);
259
260 if( wsdlContext.hasSchemaTypes() )
261 {
262 SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement(elementName);
263 if( elm != null )
264 {
265 cursor.toFirstChild();
266 xmlGenerator.createSampleForType(elm.getType(), cursor);
267 }
268 else log.error( "Could not find element [" + elementName + "] specified in part [" + part.getName() + "]" );
269 }
270
271 cursor.toParent();
272 }
273 else
274 {
275
276 cursor.beginElement( part.getName() );
277 if( typeName != null && wsdlContext.hasSchemaTypes() )
278 {
279 SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
280
281 if( type != null )
282 {
283 cursor.toFirstChild();
284 xmlGenerator.createSampleForType( type, cursor );
285 }
286 else log.error( "Could not find type [" + typeName + "] specified in part [" + part.getName() + "]" );
287 }
288
289 cursor.toParent();
290 }
291 }
292
293 private void buildDocumentRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
294 {
295 Part[] parts = WsdlUtils.getInputParts( bindingOperation );
296
297 for( int i = 0; i < parts.length; i++ )
298 {
299 Part part = parts[i];
300 if( !WsdlUtils.isAttachmentInputPart( part, bindingOperation ) &&
301 (part.getElementName() != null || part.getTypeName() != null ))
302 {
303 XmlCursor c = cursor.newCursor();
304 c.toLastChild();
305 createElementForPart( part, c, xmlGenerator );
306 c.dispose();
307 }
308 }
309 }
310
311 private void buildDocumentResponse(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
312 {
313 Part[] parts = WsdlUtils.getOutputParts( bindingOperation );
314
315 for( int i = 0; i < parts.length; i++ )
316 {
317 Part part = parts[i];
318
319 if( !WsdlUtils.isAttachmentOutputPart( part, bindingOperation ) &&
320 (part.getElementName() != null || part.getTypeName() != null ))
321 {
322 XmlCursor c = cursor.newCursor();
323 c.toLastChild();
324 createElementForPart( part, c, xmlGenerator );
325 c.dispose();
326 }
327 }
328 }
329
330 private void buildRpcRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
331 {
332
333 String ns = WsdlUtils.getSoapBodyNamespace( bindingOperation.getBindingInput()
334 .getExtensibilityElements() );
335 if( ns == null )
336 {
337 ns = wsdlContext.getDefinition().getTargetNamespace();
338 log.warn( "missing namespace on soapbind:body for RPC request, using targetNamespace instead (BP violation)" );
339 }
340
341 cursor.beginElement( new QName( ns, bindingOperation.getName() ));
342 if( xmlGenerator.isSoapEnc() )
343 cursor.insertAttributeWithValue( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "encodingStyle" ),
344 wsdlContext.getSoapVersion().getEncodingNamespace() );
345
346 Part[] inputParts = WsdlUtils.getInputParts( bindingOperation );
347 for (int i = 0; i < inputParts.length; i++)
348 {
349 Part part = inputParts[i];
350 if( WsdlUtils.isAttachmentInputPart( part, bindingOperation ))
351 {
352 if( iface.getSettings().getBoolean( WsdlSettings.ATTACHMENT_PARTS ))
353 {
354 XmlCursor c = cursor.newCursor();
355 c.toLastChild();
356 c.beginElement( part.getName() );
357 c.insertAttributeWithValue( "href", part.getName() + "Attachment" );
358 c.dispose();
359 }
360 }
361 else
362 {
363 if( wsdlContext.hasSchemaTypes() )
364 {
365 QName typeName = part.getTypeName();
366 if( typeName != null )
367 {
368 SchemaType type = wsdlContext.getInterfaceDefinition().findType( typeName );
369
370 if( type != null )
371 {
372 XmlCursor c = cursor.newCursor();
373 c.toLastChild();
374 c.insertElement( part.getName() );
375 c.toPrevToken();
376
377 xmlGenerator.createSampleForType( type, c );
378 c.dispose();
379 }
380 else
381 log.warn( "Failed to find type [" + typeName + "]" );
382 }
383 else
384 {
385 SchemaGlobalElement element = wsdlContext.getSchemaTypeLoader().findElement( part.getElementName() );
386 if( element != null )
387 {
388 XmlCursor c = cursor.newCursor();
389 c.toLastChild();
390 c.insertElement( element.getName() );
391 c.toPrevToken();
392
393 xmlGenerator.createSampleForType( element.getType(), c );
394 c.dispose();
395 }
396 else
397 log.warn( "Failed to find element [" + part.getElementName() + "]" );
398 }
399 }
400 }
401 }
402 }
403
404 private void buildRpcResponse(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
405 {
406
407 String ns = WsdlUtils.getSoapBodyNamespace( bindingOperation.getBindingOutput()
408 .getExtensibilityElements() );
409
410 if( ns == null )
411 {
412 ns = wsdlContext.getDefinition().getTargetNamespace();
413 log.warn( "missing namespace on soapbind:body for RPC response, using targetNamespace instead (BP violation)" );
414 }
415
416 cursor.beginElement( new QName( ns, bindingOperation.getName() + "Response" ));
417 if( xmlGenerator.isSoapEnc() )
418 cursor.insertAttributeWithValue( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "encodingStyle" ),
419 wsdlContext.getSoapVersion().getEncodingNamespace() );
420
421 Part[] inputParts = WsdlUtils.getOutputParts( bindingOperation );
422 for (int i = 0; i < inputParts.length; i++)
423 {
424 Part part = inputParts[i];
425 if( WsdlUtils.isAttachmentOutputPart( part, bindingOperation ))
426 {
427 if( iface.getSettings().getBoolean( WsdlSettings.ATTACHMENT_PARTS ))
428 {
429 XmlCursor c = cursor.newCursor();
430 c.toLastChild();
431 c.beginElement( part.getName() );
432 c.insertAttributeWithValue( "href", part.getName() + "Attachment" );
433 c.dispose();
434 }
435 }
436 else
437 {
438 if( wsdlContext.hasSchemaTypes() )
439 {
440 QName typeName = part.getTypeName();
441 if( typeName != null )
442 {
443 SchemaType type = wsdlContext.getInterfaceDefinition().findType( typeName );
444
445 if( type != null )
446 {
447 XmlCursor c = cursor.newCursor();
448 c.toLastChild();
449 c.insertElement( part.getName() );
450 c.toPrevToken();
451
452 xmlGenerator.createSampleForType( type, c );
453 c.dispose();
454 }
455 else
456 log.warn( "Failed to find type [" + typeName + "]" );
457 }
458 else
459 {
460 SchemaGlobalElement element = wsdlContext.getSchemaTypeLoader().findElement( part.getElementName() );
461 if( element != null )
462 {
463 XmlCursor c = cursor.newCursor();
464 c.toLastChild();
465 c.insertElement( element.getName() );
466 c.toPrevToken();
467
468 xmlGenerator.createSampleForType( element.getType(), c );
469 c.dispose();
470 }
471 else
472 log.warn( "Failed to find element [" + part.getElementName() + "]" );
473 }
474 }
475 }
476 }
477 }
478
479 public void setWsdlContext( WsdlContext wsdlContext )
480 {
481 this.wsdlContext = wsdlContext;
482 }
483
484 public void setInterface(WsdlInterface iface )
485 {
486 this.iface = iface;
487 }
488
489 public String buildSoapMessageFromOutput( BindingOperation bindingOperation, boolean buildOptional ) throws Exception
490 {
491 return buildSoapMessageFromOutput( bindingOperation, buildOptional, true );
492 }
493
494 public String buildSoapMessageFromOutput( BindingOperation bindingOperation, boolean buildOptional,
495 boolean alwaysBuildHeaders )
496 throws Exception
497 {
498 boolean inputSoapEncoded = WsdlUtils.isInputSoapEncoded( bindingOperation );
499 SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
500 xmlGenerator.setIgnoreOptional( !buildOptional );
501 xmlGenerator.setMultiValues(multiValues);
502
503 XmlObject object = XmlObject.Factory.newInstance();
504 XmlCursor cursor = object.newCursor();
505 cursor.toNextToken();
506 cursor.beginElement( wsdlContext.getSoapVersion().getEnvelopeQName() );
507
508 if( inputSoapEncoded )
509 {
510 cursor.insertNamespace( "xsi", Constants.XSI_NS );
511 cursor.insertNamespace( "xsd", Constants.XSD_NS );
512 }
513
514 cursor.toFirstChild();
515
516 cursor.beginElement(wsdlContext.getSoapVersion().getBodyQName());
517 cursor.toFirstChild();
518
519 if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
520 {
521 buildRpcResponse( bindingOperation, cursor, xmlGenerator );
522 }
523 else
524 {
525 buildDocumentResponse( bindingOperation, cursor, xmlGenerator );
526 }
527
528 if(alwaysBuildHeaders)
529 {
530
531
532 BindingOutput bindingOutput = bindingOperation.getBindingOutput();
533 List extensibilityElements = bindingOutput.getExtensibilityElements();
534 List<SoapHeader> soapHeaders = WsdlUtils.getSoapHeaders( extensibilityElements );
535 addHeaders(soapHeaders, cursor, xmlGenerator);
536 }
537 cursor.dispose();
538
539 try
540 {
541 StringWriter writer = new StringWriter();
542 XmlUtils.serializePretty( object, writer );
543 return writer.toString();
544 }
545 catch( Exception e )
546 {
547 SoapUI.logError( e );
548 return object.xmlText();
549 }
550 }
551
552
553 public String buildFault( FaultPart faultPart )
554 {
555 SampleXmlUtil generator = new SampleXmlUtil( false );
556 generator.setExampleContent( false );
557 generator.setTypeComment( false );
558 generator.setMultiValues(multiValues);
559 String faultResponse = iface.getMessageBuilder().buildEmptyFault();
560
561 XmlCursor cursor = null;
562 try
563 {
564 XmlObject xmlObject = XmlObject.Factory.parse( faultResponse );
565 XmlObject[] detail = xmlObject.selectPath( "//detail" );
566 cursor = detail[0].newCursor();
567
568 cursor.toFirstContentToken();
569
570 generator.setTypeComment( true );
571 generator.setIgnoreOptional( iface.getSettings().getBoolean( WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS ) );
572
573 for( Part part : faultPart.getWsdlParts() )
574 createElementForPart( part, cursor, generator );
575
576 faultResponse = xmlObject.xmlText( new XmlOptions().setSaveAggressiveNamespaces().setSavePrettyPrint());
577 }
578 catch( Exception e1 )
579 {
580 SoapUI.logError( e1 );
581 }
582 finally
583 {
584 if( cursor != null )
585 cursor.dispose();
586 }
587
588 return faultResponse;
589 }
590 }