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