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.util.List;
16
17 import javax.wsdl.BindingOperation;
18 import javax.wsdl.Message;
19 import javax.wsdl.Part;
20 import javax.xml.namespace.QName;
21
22 import org.apache.xmlbeans.XmlCursor;
23 import org.apache.xmlbeans.XmlException;
24 import org.apache.xmlbeans.XmlObject;
25 import org.w3c.dom.Document;
26 import org.w3c.dom.Element;
27 import org.w3c.dom.Node;
28 import org.w3c.dom.NodeList;
29
30 import com.eviware.soapui.SoapUI;
31 import com.eviware.soapui.impl.wsdl.WsdlOperation;
32 import com.eviware.soapui.impl.wsdl.mock.DispatchException;
33 import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils;
34 import com.eviware.soapui.model.iface.Attachment;
35 import com.eviware.soapui.support.StringUtils;
36 import com.eviware.soapui.support.types.StringToStringsMap;
37 import com.eviware.soapui.support.xml.XmlUtils;
38
39 /***
40 * SOAP-related utility-methods..
41 *
42 * @author ole.matzura
43 */
44
45 public class SoapUtils
46 {
47 public static boolean isSoapFault( String responseContent, SoapVersion soapVersion ) throws XmlException
48 {
49 if( StringUtils.isNullOrEmpty( responseContent ) )
50 return false;
51
52
53 if( responseContent.indexOf( ":Fault" ) > 0 || responseContent.indexOf( "<Fault" ) > 0 )
54 {
55 XmlObject xml = XmlObject.Factory.parse( responseContent );
56 XmlObject[] paths = xml.selectPath( "declare namespace env='" + soapVersion.getEnvelopeNamespace() + "';"
57 + "//env:Fault" );
58 if( paths.length > 0 )
59 return true;
60 }
61
62 return false;
63 }
64
65 /***
66 * Init soapversion from content-type header.. should envelope be checked
67 * and/or override?
68 *
69 * @param xmlObject
70 */
71
72 public static SoapVersion deduceSoapVersion( String contentType, XmlObject xmlObject )
73 {
74 if( xmlObject != null )
75 {
76 Element elm = ( ( Document )( xmlObject.getDomNode() ) ).getDocumentElement();
77 if( elm.getLocalName().equals( "Envelope" ) )
78 {
79 if( elm.getNamespaceURI().equals( SoapVersion.Soap11.getEnvelopeNamespace() ) )
80 return SoapVersion.Soap11;
81 else if( elm.getNamespaceURI().equals( SoapVersion.Soap12.getEnvelopeNamespace() ) )
82 return SoapVersion.Soap12;
83 }
84 }
85
86 SoapVersion soapVersion = null;
87
88 if( StringUtils.isNullOrEmpty( contentType ) )
89 return null;
90
91 soapVersion = contentType.startsWith( SoapVersion.Soap11.getContentType() ) ? SoapVersion.Soap11 : null;
92 soapVersion = soapVersion == null && contentType.startsWith( SoapVersion.Soap12.getContentType() ) ? SoapVersion.Soap12
93 : soapVersion;
94 if( soapVersion == null && contentType.startsWith( "application/xop+xml" ) )
95 {
96 if( contentType.indexOf( "type=\"" + SoapVersion.Soap11.getContentType() + "\"" ) > 0 )
97 soapVersion = SoapVersion.Soap11;
98 else if( contentType.indexOf( "type=\"" + SoapVersion.Soap12.getContentType() + "\"" ) > 0 )
99 soapVersion = SoapVersion.Soap12;
100 }
101
102 return soapVersion;
103 }
104
105 public static String getSoapAction( SoapVersion soapVersion, StringToStringsMap headers )
106 {
107 String soapAction = null;
108 String contentType = headers.get( "Content-Type", "" );
109
110 if( soapVersion == SoapVersion.Soap11 )
111 {
112 soapAction = headers.get( "SOAPAction", "" );
113 }
114 else if( soapVersion == SoapVersion.Soap12 )
115 {
116 int ix = contentType.indexOf( "action=" );
117 if( ix > 0 )
118 {
119 int endIx = contentType.indexOf( ';', ix );
120 soapAction = endIx == -1 ? contentType.substring( ix + 7 ) : contentType.substring( ix + 7, endIx );
121 }
122 }
123
124 soapAction = StringUtils.unquote( soapAction );
125
126 return soapAction;
127 }
128
129 public static XmlObject getBodyElement( XmlObject messageObject, SoapVersion soapVersion ) throws XmlException
130 {
131 XmlObject[] envelope = messageObject.selectChildren( soapVersion.getEnvelopeQName() );
132 if( envelope.length != 1 )
133 throw new XmlException( "Missing/Invalid SOAP Envelope, expecting [" + soapVersion.getEnvelopeQName() + "]" );
134
135 XmlObject[] body = envelope[0].selectChildren( soapVersion.getBodyQName() );
136 if( body.length != 1 )
137 throw new XmlException( "Missing/Invalid SOAP Body, expecting [" + soapVersion.getBodyQName() + "]" );
138
139 return body[0];
140 }
141
142 public static XmlObject getHeaderElement( XmlObject messageObject, SoapVersion soapVersion, boolean create )
143 throws XmlException
144 {
145 XmlObject[] envelope = messageObject.selectChildren( soapVersion.getEnvelopeQName() );
146 if( envelope.length != 1 )
147 throw new XmlException( "Missing/Invalid SOAP Envelope, expecting [" + soapVersion.getEnvelopeQName() + "]" );
148
149 QName headerQName = soapVersion.getHeaderQName();
150 XmlObject[] header = envelope[0].selectChildren( headerQName );
151 if( header.length == 0 && create )
152 {
153 Element elm = ( Element )envelope[0].getDomNode();
154 Element headerElement = elm.getOwnerDocument().createElementNS( headerQName.getNamespaceURI(),
155 headerQName.getLocalPart() );
156
157 elm.insertBefore( headerElement, elm.getFirstChild() );
158
159 header = envelope[0].selectChildren( headerQName );
160 }
161
162 return header.length == 0 ? null : header[0];
163 }
164
165 public static XmlObject getContentElement( XmlObject messageObject, SoapVersion soapVersion ) throws XmlException
166 {
167 if( messageObject == null )
168 return null;
169
170 XmlObject bodyElement = SoapUtils.getBodyElement( messageObject, soapVersion );
171 if( bodyElement != null )
172 {
173 XmlCursor cursor = bodyElement.newCursor();
174
175 try
176 {
177 if( cursor.toFirstChild() )
178 {
179 while( !cursor.isContainer() )
180 cursor.toNextSibling();
181
182 if( cursor.isContainer() )
183 {
184 return cursor.getObject();
185 }
186 }
187 }
188 catch( Exception e )
189 {
190 SoapUI.logError( e );
191 }
192 finally
193 {
194 cursor.dispose();
195 }
196 }
197
198 return null;
199 }
200
201 @SuppressWarnings( "unchecked" )
202 public static WsdlOperation findOperationForRequest( SoapVersion soapVersion, String soapAction,
203 XmlObject requestContent, List<WsdlOperation> operations, boolean requireSoapVersionMatch,
204 boolean requireSoapActionMatch, Attachment[] attachments ) throws Exception
205 {
206 XmlObject contentElm = getContentElement( requestContent, soapVersion );
207 if( contentElm == null )
208 {
209 for( WsdlOperation operation : operations )
210 {
211 if( operation.getAction().equals( soapAction )
212 && operation.getBindingOperation().getOperation().getInput().getMessage().getParts().size() == 0 )
213 {
214 return operation;
215 }
216 }
217
218 return null;
219 }
220
221 QName contentQName = XmlUtils.getQName( contentElm.getDomNode() );
222 NodeList contentChildNodes = null;
223
224 for( int c = 0; c < operations.size(); c++ )
225 {
226 WsdlOperation wsdlOperation = operations.get( c );
227 String action = wsdlOperation.getAction();
228
229
230 if( !requireSoapActionMatch
231 || ( ( soapAction == null && wsdlOperation.getAction() == null ) || ( action != null && action
232 .equals( soapAction ) ) ) )
233 {
234 QName qname = wsdlOperation.getRequestBodyElementQName();
235
236 if( !contentQName.equals( qname ) )
237 continue;
238
239 SoapVersion ifaceSoapVersion = wsdlOperation.getInterface().getSoapVersion();
240
241 if( requireSoapVersionMatch && ifaceSoapVersion != soapVersion )
242 {
243 continue;
244 }
245
246
247 if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_DOCUMENT ) )
248 {
249
250 BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
251 Message message = bindingOperation.getOperation().getInput().getMessage();
252 List<Part> parts = message.getOrderedParts( null );
253
254 for( int x = 0; x < parts.size(); x++ )
255 {
256
257 if( WsdlUtils.isAttachmentInputPart( parts.get( x ), bindingOperation ) )
258 {
259 for( Attachment attachment : attachments )
260 {
261 if( attachment.getPart().equals( parts.get( x ).getName() ) )
262 {
263 parts.remove( x );
264 x-- ;
265 }
266 }
267 }
268 else
269 {
270 parts.remove( x );
271 x-- ;
272 }
273 }
274
275
276 if( parts.isEmpty() )
277 {
278 return wsdlOperation;
279 }
280 }
281 else if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_RPC ) )
282 {
283 BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
284 Message message = bindingOperation.getOperation().getInput().getMessage();
285 List<Part> parts = message.getOrderedParts( null );
286
287 if( contentChildNodes == null )
288 contentChildNodes = XmlUtils.getChildElements( ( Element )contentElm.getDomNode() );
289
290 int i = 0;
291
292 if( parts.size() > 0 )
293 {
294 for( int x = 0; x < parts.size(); x++ )
295 {
296 if( WsdlUtils.isAttachmentInputPart( parts.get( x ), bindingOperation ) )
297 {
298 for( Attachment attachment : attachments )
299 {
300 if( attachment.getPart().equals( parts.get( x ).getName() ) )
301 {
302 parts.remove( x );
303 x-- ;
304 }
305 }
306 }
307
308
309 if( x >= 0 && WsdlUtils.isHeaderInputPart( parts.get( x ), message, bindingOperation ) )
310 {
311 parts.remove( x );
312 x-- ;
313 }
314 }
315
316 for( ; i < contentChildNodes.getLength() && !parts.isEmpty(); i++ )
317 {
318 Node item = contentChildNodes.item( i );
319 if( item.getNodeType() != Node.ELEMENT_NODE )
320 continue;
321
322 int j = 0;
323 while( ( j < parts.size() ) && ( !item.getNodeName().equals( parts.get( j ).getName() ) ) )
324 {
325 Part part = parts.get( j );
326 if( part.getElementName() != null )
327 {
328 QName qn = part.getElementName();
329 if( item.getLocalName().equals( qn.getLocalPart() )
330 && item.getNamespaceURI().equals( qn.getNamespaceURI() ) )
331 break;
332 }
333 else
334 {
335 if( item.getNodeName().equals( parts.get( j ).getName() ) )
336 break;
337 }
338
339 j++ ;
340 }
341
342 if( j == parts.size() )
343 break;
344
345 parts.remove( j );
346 }
347 }
348
349
350 if( i == contentChildNodes.getLength() && parts.isEmpty() )
351 {
352 return wsdlOperation;
353 }
354 }
355 }
356 }
357
358 throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element ["
359 + contentQName + "] with SOAP Version [" + soapVersion + "]" );
360 }
361
362 @SuppressWarnings( "unchecked" )
363 public static WsdlOperation findOperationForResponse( SoapVersion soapVersion, String soapAction,
364 XmlObject responseContent, List<WsdlOperation> operations, boolean requireSoapVersionMatch,
365 boolean requireSoapActionMatch ) throws Exception
366 {
367 XmlObject contentElm = getContentElement( responseContent, soapVersion );
368 if( contentElm == null )
369 return null;
370
371 QName contentQName = XmlUtils.getQName( contentElm.getDomNode() );
372 NodeList contentChildNodes = null;
373
374 for( int c = 0; c < operations.size(); c++ )
375 {
376 WsdlOperation wsdlOperation = operations.get( c );
377 String action = wsdlOperation.getAction();
378
379
380 if( !requireSoapActionMatch
381 || ( ( soapAction == null && wsdlOperation.getAction() == null ) || ( action != null && action
382 .equals( soapAction ) ) ) )
383 {
384 QName qname = wsdlOperation.getResponseBodyElementQName();
385
386 if( !contentQName.equals( qname ) )
387 continue;
388
389 SoapVersion ifaceSoapVersion = wsdlOperation.getInterface().getSoapVersion();
390
391 if( requireSoapVersionMatch && ifaceSoapVersion != soapVersion )
392 {
393 continue;
394 }
395
396
397 if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_DOCUMENT ) )
398 {
399
400 return wsdlOperation;
401 }
402 else if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_RPC ) )
403 {
404 BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
405 Message message = bindingOperation.getOperation().getOutput().getMessage();
406 List<Part> parts = message.getOrderedParts( null );
407
408 if( contentChildNodes == null )
409 contentChildNodes = XmlUtils.getChildElements( ( Element )contentElm.getDomNode() );
410
411 int i = 0;
412
413 if( parts.size() > 0 )
414 {
415 for( int x = 0; x < parts.size(); x++ )
416 {
417 if( WsdlUtils.isAttachmentOutputPart( parts.get( x ), bindingOperation )
418 || WsdlUtils.isHeaderOutputPart( parts.get( x ), message, bindingOperation ) )
419 {
420 parts.remove( x );
421 x-- ;
422 }
423 }
424
425 for( ; i < contentChildNodes.getLength() && !parts.isEmpty(); i++ )
426 {
427 Node item = contentChildNodes.item( i );
428 if( item.getNodeType() != Node.ELEMENT_NODE )
429 continue;
430
431 int j = 0;
432 while( ( j < parts.size() ) && ( !item.getNodeName().equals( parts.get( j ).getName() ) ) )
433 {
434 Part part = parts.get( j );
435 if( part.getElementName() != null )
436 {
437 QName qn = part.getElementName();
438 if( item.getLocalName().equals( qn.getLocalPart() )
439 && item.getNamespaceURI().equals( qn.getNamespaceURI() ) )
440 break;
441 }
442 else
443 {
444 if( item.getNodeName().equals( parts.get( j ).getName() ) )
445 break;
446 }
447
448 j++ ;
449 }
450
451 if( j == parts.size() )
452 break;
453
454 parts.remove( j );
455 }
456 }
457
458
459 if( i == contentChildNodes.getLength() && parts.isEmpty() )
460 {
461 return wsdlOperation;
462 }
463 }
464 }
465 }
466
467 throw new DispatchException( "Missing response operation for soapAction [" + soapAction + "] and body element ["
468 + contentQName + "] with SOAP Version [" + soapVersion + "]" );
469 }
470
471 public static String removeEmptySoapHeaders( String content, SoapVersion soapVersion ) throws XmlException
472 {
473 XmlObject xmlObject = XmlObject.Factory.parse( content );
474 XmlObject[] selectPath = xmlObject.selectPath( "declare namespace soap='" + soapVersion.getEnvelopeNamespace()
475 + "';/soap:Envelope/soap:Header" );
476 if( selectPath.length > 0 )
477 {
478 Node domNode = selectPath[0].getDomNode();
479 if( !domNode.hasChildNodes() && !domNode.hasAttributes() )
480 {
481 domNode.getParentNode().removeChild( domNode );
482 return xmlObject.xmlText();
483 }
484 }
485
486 return content;
487 }
488
489 public static SoapVersion deduceSoapVersion( String requestContentType, String requestContent )
490 {
491 try
492 {
493 return deduceSoapVersion( requestContentType, XmlObject.Factory.parse( requestContent ) );
494 }
495 catch( XmlException e )
496 {
497 return deduceSoapVersion( requestContentType, ( XmlObject )null );
498 }
499 }
500
501 public static String transferSoapHeaders( String requestContent, String newRequest, SoapVersion soapVersion )
502 {
503 try
504 {
505 XmlObject source = XmlObject.Factory.parse( requestContent );
506 String headerXPath = "declare namespace ns='" + soapVersion.getEnvelopeNamespace() + "'; //ns:Header";
507 XmlObject[] header = source.selectPath( headerXPath );
508 if( header.length == 1 )
509 {
510 Element headerElm = ( Element )header[0].getDomNode();
511 NodeList childNodes = headerElm.getChildNodes();
512 if( childNodes.getLength() > 0 )
513 {
514 XmlObject dest = XmlObject.Factory.parse( newRequest );
515 header = dest.selectPath( headerXPath );
516 Element destElm = null;
517
518 if( header.length == 0 )
519 {
520 Element docElm = ( ( Document )dest.getDomNode() ).getDocumentElement();
521
522 destElm = ( Element )docElm.insertBefore( docElm.getOwnerDocument().createElementNS(
523 soapVersion.getEnvelopeNamespace(), docElm.getPrefix() + ":Header" ), XmlUtils
524 .getFirstChildElementNS( docElm, soapVersion.getBodyQName() ) );
525 }
526 else
527 {
528 destElm = ( Element )header[0].getDomNode();
529 }
530
531 for( int c = 0; c < childNodes.getLength(); c++ )
532 {
533 destElm.appendChild( destElm.getOwnerDocument().importNode( childNodes.item( c ), true ) );
534 }
535
536 return dest.xmlText();
537 }
538 }
539 }
540 catch( XmlException e )
541 {
542 SoapUI.logError( e );
543 }
544
545 return newRequest;
546 }
547 }