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 boolean inputSoapEncoded = WsdlUtils.isInputSoapEncoded( bindingOperation );
171 SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
172 xmlGenerator.setIgnoreOptional( !buildOptional );
173
174 XmlObject object = XmlObject.Factory.newInstance();
175 XmlCursor cursor = object.newCursor();
176 cursor.toNextToken();
177 cursor.beginElement( wsdlContext.getSoapVersion().getEnvelopeQName() );
178
179 if( inputSoapEncoded )
180 {
181 cursor.insertNamespace( "xsi", Constants.XSI_NS );
182 cursor.insertNamespace( "xsd", Constants.XSD_NS );
183 }
184
185 cursor.toFirstChild();
186
187 cursor.beginElement(wsdlContext.getSoapVersion().getBodyQName());
188 cursor.toFirstChild();
189
190 if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
191 {
192 buildRpcRequest( bindingOperation, cursor, xmlGenerator );
193 }
194 else
195 {
196 buildDocumentRequest( bindingOperation, cursor, xmlGenerator );
197 }
198
199 addHeaders( WsdlUtils.getSoapHeaders( bindingOperation.getBindingInput().getExtensibilityElements()),
200 cursor, xmlGenerator);
201 cursor.dispose();
202
203 try
204 {
205 StringWriter writer = new StringWriter();
206 XmlUtils.serializePretty( object, writer );
207 return writer.toString();
208 }
209 catch( Exception e )
210 {
211 SoapUI.logError( e );
212 return object.xmlText();
213 }
214 }
215
216 private void addHeaders(List<SoapHeader> headers, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
217 {
218
219 cursor.toStartDoc();
220 cursor.toChild(wsdlContext.getSoapVersion().getEnvelopeQName());
221 cursor.toFirstChild();
222
223 cursor.beginElement(wsdlContext.getSoapVersion().getHeaderQName());
224 cursor.toFirstChild();
225
226 for (int i = 0; i < headers.size(); i++)
227 {
228 SoapHeader header = (SoapHeader) headers.get(i);
229
230 Message message = wsdlContext.getDefinition().getMessage( header.getMessage() );
231 if( message == null )
232 {
233 log.error( "Missing message for header: " + header.getMessage() );
234 continue;
235 }
236
237 Part part = message.getPart( header.getPart() );
238
239 if( part != null )
240 createElementForPart( part, cursor, xmlGenerator );
241 else
242 log.error( "Missing part for header; " + header.getPart() );
243 }
244 }
245
246 public void createElementForPart(Part part, XmlCursor cursor, SampleXmlUtil xmlGenerator ) throws Exception
247 {
248 QName elementName = part.getElementName();
249 QName typeName = part.getTypeName();
250
251 if( elementName != null )
252 {
253 cursor.beginElement(elementName);
254
255 if( wsdlContext.hasSchemaTypes() )
256 {
257 SchemaGlobalElement elm = wsdlContext.getSchemaTypeLoader().findElement(elementName);
258 if( elm != null )
259 {
260 cursor.toFirstChild();
261 xmlGenerator.createSampleForType(elm.getType(), cursor);
262 }
263 else log.error( "Could not find element [" + elementName + "] specified in part [" + part.getName() + "]" );
264 }
265
266 cursor.toParent();
267 }
268 else
269 {
270 cursor.beginElement( new QName( wsdlContext.getDefinition().getTargetNamespace(), part.getName() ));
271 if( typeName != null && wsdlContext.hasSchemaTypes() )
272 {
273 SchemaType type = wsdlContext.getSchemaTypeLoader().findType( typeName );
274
275 if( type != null )
276 {
277 cursor.toFirstChild();
278 xmlGenerator.createSampleForType( type, cursor );
279 }
280 else log.error( "Could not find type [" + typeName + "] specified in part [" + part.getName() + "]" );
281 }
282
283 cursor.toParent();
284 }
285 }
286
287 private void buildDocumentRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
288 {
289 Part[] parts = WsdlUtils.getInputParts( bindingOperation );
290
291 for( int i = 0; i < parts.length; i++ )
292 {
293 if( !WsdlUtils.isAttachmentInputPart( parts[i], bindingOperation ))
294 {
295 XmlCursor c = cursor.newCursor();
296 c.toLastChild();
297 createElementForPart( parts[i], c, xmlGenerator );
298 c.dispose();
299 }
300 }
301 }
302
303 private void buildDocumentResponse(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
304 {
305 Part[] parts = WsdlUtils.getOutputParts( bindingOperation );
306
307 for( int i = 0; i < parts.length; i++ )
308 {
309 if( !WsdlUtils.isAttachmentOutputPart( parts[i], bindingOperation ))
310 {
311 XmlCursor c = cursor.newCursor();
312 c.toLastChild();
313 createElementForPart( parts[i], c, xmlGenerator );
314 c.dispose();
315 }
316 }
317 }
318
319 private void buildRpcRequest(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
320 {
321
322 String ns = WsdlUtils.getSoapBodyNamespace( bindingOperation.getBindingInput()
323 .getExtensibilityElements() );
324 if( ns == null )
325 {
326 ns = wsdlContext.getDefinition().getTargetNamespace();
327 log.warn( "missing namespace on soapbind:body, using targetNamespace instead (BP violation)" );
328 }
329
330 cursor.beginElement( new QName( ns, bindingOperation.getName() ));
331 if( xmlGenerator.isSoapEnc() )
332 cursor.insertAttributeWithValue( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "encodingStyle" ),
333 wsdlContext.getSoapVersion().getEncodingNamespace() );
334
335 Part[] inputParts = WsdlUtils.getInputParts( bindingOperation );
336 for (int i = 0; i < inputParts.length; i++)
337 {
338 Part part = inputParts[i];
339 if( WsdlUtils.isAttachmentInputPart( part, bindingOperation ))
340 {
341 if( iface.getSettings().getBoolean( WsdlSettings.ATTACHMENT_PARTS ))
342 {
343 XmlCursor c = cursor.newCursor();
344 c.toLastChild();
345 c.beginElement( part.getName() );
346 c.insertAttributeWithValue( "href", part.getName() + "Attachment" );
347 c.dispose();
348 }
349 }
350 else
351 {
352 if( wsdlContext.hasSchemaTypes() )
353 {
354 QName typeName = part.getTypeName();
355 if( typeName != null )
356 {
357 SchemaType type = wsdlContext.findType( typeName );
358
359 if( type != null )
360 {
361 XmlCursor c = cursor.newCursor();
362 c.toLastChild();
363 c.insertElement( part.getName() );
364 c.toPrevToken();
365
366 xmlGenerator.createSampleForType( type, c );
367 c.dispose();
368 }
369 else
370 log.warn( "Failed to find type [" + typeName + "]" );
371 }
372 else
373 {
374 SchemaGlobalElement element = wsdlContext.getSchemaTypeLoader().findElement( part.getElementName() );
375 if( element != null )
376 {
377 XmlCursor c = cursor.newCursor();
378 c.toLastChild();
379 c.insertElement( element.getName() );
380 c.toPrevToken();
381
382 xmlGenerator.createSampleForType( element.getType(), c );
383 c.dispose();
384 }
385 else
386 log.warn( "Failed to find element [" + part.getElementName() + "]" );
387 }
388 }
389 }
390 }
391 }
392
393 private void buildRpcResponse(BindingOperation bindingOperation, XmlCursor cursor, SampleXmlUtil xmlGenerator) throws Exception
394 {
395
396 String ns = WsdlUtils.getSoapBodyNamespace( bindingOperation.getBindingOutput()
397 .getExtensibilityElements() );
398
399 if( ns == null )
400 {
401 ns = wsdlContext.getDefinition().getTargetNamespace();
402 log.warn( "missing namespace on soapbind:body, using targetNamespace instead (BP violation)" );
403 }
404
405 cursor.beginElement( new QName( ns, bindingOperation.getName() + "Response" ));
406 if( xmlGenerator.isSoapEnc() )
407 cursor.insertAttributeWithValue( new QName( wsdlContext.getSoapVersion().getEnvelopeNamespace(), "encodingStyle" ),
408 wsdlContext.getSoapVersion().getEncodingNamespace() );
409
410 Part[] inputParts = WsdlUtils.getOutputParts( bindingOperation );
411 for (int i = 0; i < inputParts.length; i++)
412 {
413 Part part = inputParts[i];
414 if( WsdlUtils.isAttachmentOutputPart( part, bindingOperation ))
415 {
416 if( iface.getSettings().getBoolean( WsdlSettings.ATTACHMENT_PARTS ))
417 {
418 XmlCursor c = cursor.newCursor();
419 c.toLastChild();
420 c.beginElement( part.getName() );
421 c.insertAttributeWithValue( "href", part.getName() + "Attachment" );
422 c.dispose();
423 }
424 }
425 else
426 {
427 if( wsdlContext.hasSchemaTypes() )
428 {
429 QName typeName = part.getTypeName();
430 if( typeName != null )
431 {
432 SchemaType type = wsdlContext.findType( typeName );
433
434 if( type != null )
435 {
436 XmlCursor c = cursor.newCursor();
437 c.toLastChild();
438 c.insertElement( part.getName() );
439 c.toPrevToken();
440
441 xmlGenerator.createSampleForType( type, c );
442 c.dispose();
443 }
444 else
445 log.warn( "Failed to find type [" + typeName + "]" );
446 }
447 else
448 {
449 SchemaGlobalElement element = wsdlContext.getSchemaTypeLoader().findElement( part.getElementName() );
450 if( element != null )
451 {
452 XmlCursor c = cursor.newCursor();
453 c.toLastChild();
454 c.insertElement( element.getName() );
455 c.toPrevToken();
456
457 xmlGenerator.createSampleForType( element.getType(), c );
458 c.dispose();
459 }
460 else
461 log.warn( "Failed to find element [" + part.getElementName() + "]" );
462 }
463 }
464 }
465 }
466 }
467
468 public void setWsdlContext( WsdlContext wsdlContext )
469 {
470 this.wsdlContext = wsdlContext;
471 }
472
473 public void setInterface(WsdlInterface iface )
474 {
475 this.iface = iface;
476 }
477
478 public String buildSoapResponse( BindingOperation bindingOperation, boolean buildOptional ) throws Exception
479 {
480 boolean inputSoapEncoded = WsdlUtils.isInputSoapEncoded( bindingOperation );
481 SampleXmlUtil xmlGenerator = new SampleXmlUtil(inputSoapEncoded);
482 xmlGenerator.setIgnoreOptional( !buildOptional );
483
484 XmlObject object = XmlObject.Factory.newInstance();
485 XmlCursor cursor = object.newCursor();
486 cursor.toNextToken();
487 cursor.beginElement( wsdlContext.getSoapVersion().getEnvelopeQName() );
488
489 if( inputSoapEncoded )
490 {
491 cursor.insertNamespace( "xsi", Constants.XSI_NS );
492 cursor.insertNamespace( "xsd", Constants.XSD_NS );
493 }
494
495 cursor.toFirstChild();
496
497 cursor.beginElement(wsdlContext.getSoapVersion().getBodyQName());
498 cursor.toFirstChild();
499
500 if( WsdlUtils.isRpc( wsdlContext.getDefinition(), bindingOperation ))
501 {
502 buildRpcResponse( bindingOperation, cursor, xmlGenerator );
503 }
504 else
505 {
506 buildDocumentResponse( bindingOperation, cursor, xmlGenerator );
507 }
508
509 addHeaders(WsdlUtils.getSoapHeaders( bindingOperation.getBindingOutput()
510 .getExtensibilityElements() ), cursor, xmlGenerator);
511 cursor.dispose();
512
513 try
514 {
515 StringWriter writer = new StringWriter();
516 XmlUtils.serializePretty( object, writer );
517 return writer.toString();
518 }
519 catch( Exception e )
520 {
521 SoapUI.logError( e );
522 return object.xmlText();
523 }
524 }
525
526
527 public String buildFault( FaultPart faultPart )
528 {
529 SampleXmlUtil generator = new SampleXmlUtil( false );
530 generator.setExampleContent( false );
531 generator.setTypeComment( false );
532 String faultResponse = iface.getMessageBuilder().buildEmptyFault();
533
534 XmlCursor cursor = null;
535 try
536 {
537 XmlObject xmlObject = XmlObject.Factory.parse( faultResponse );
538 XmlObject[] detail = xmlObject.selectPath( "//detail" );
539 cursor = detail[0].newCursor();
540
541 cursor.toFirstContentToken();
542
543 generator.setTypeComment( true );
544 generator.setIgnoreOptional( iface.getSettings().getBoolean( WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS ) );
545
546 for( Part part : faultPart.getWsdlParts() )
547 createElementForPart( part, cursor, generator );
548
549 faultResponse = xmlObject.xmlText( new XmlOptions().setSaveAggressiveNamespaces().setSavePrettyPrint());
550 }
551 catch( Exception e1 )
552 {
553 SoapUI.logError( e1 );
554 }
555 finally
556 {
557 if( cursor != null )
558 cursor.dispose();
559 }
560
561 return faultResponse;
562 }
563 }