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