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