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