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.support.StringUtils;
35 import com.eviware.soapui.support.types.StringToStringMap;
36 import com.eviware.soapui.support.xml.XmlUtils;
37
38 /***
39 * SOAP-related utility-methods..
40 *
41 * @author ole.matzura
42 */
43
44 public class SoapUtils
45 {
46 public static boolean isSoapFault( String responseContent, SoapVersion soapVersion ) throws XmlException
47 {
48 if( StringUtils.isNullOrEmpty( responseContent ))
49 return false;
50
51
52 if( responseContent.indexOf( ":Fault" ) > 0 || responseContent.indexOf( "<Fault" ) > 0 )
53 {
54 XmlObject xml = XmlObject.Factory.parse( responseContent );
55 XmlObject[] paths = xml.selectPath( "declare namespace env='" + soapVersion.getEnvelopeNamespace() + "';" +
56 "//env:Fault");
57 if( paths.length > 0 )
58 return true;
59 }
60
61 return false;
62 }
63
64 /***
65 * Init soapversion from content-type header.. should envelope be checked and/or override?
66 * @param xmlObject
67 */
68
69 public static SoapVersion deduceSoapVersion( String contentType, XmlObject xmlObject )
70 {
71 if( xmlObject != null )
72 {
73 Element elm = ((Document)(xmlObject.getDomNode())).getDocumentElement();
74 if( elm.getLocalName().equals("Envelope"))
75 {
76 if( elm.getNamespaceURI().equals( SoapVersion.Soap11.getEnvelopeNamespace()))
77 return SoapVersion.Soap11;
78 else if( elm.getNamespaceURI().equals( SoapVersion.Soap12.getEnvelopeNamespace()))
79 return SoapVersion.Soap12;
80 }
81 }
82
83 SoapVersion soapVersion = null;
84
85 if( StringUtils.isNullOrEmpty( contentType ) )
86 return null;
87
88 soapVersion = contentType.startsWith( SoapVersion.Soap11.getContentType() ) ? SoapVersion.Soap11 : null;
89 soapVersion = soapVersion == null && contentType.startsWith( SoapVersion.Soap12.getContentType() ) ? SoapVersion.Soap12 : soapVersion;
90 if( soapVersion == null && contentType.startsWith( "application/xop+xml" ))
91 {
92 if( contentType.indexOf( "type=\"" + SoapVersion.Soap11.getContentType() + "\"" ) > 0 )
93 soapVersion = SoapVersion.Soap11;
94 else if( contentType.indexOf( "type=\"" + SoapVersion.Soap12.getContentType() + "\"" ) > 0 )
95 soapVersion = SoapVersion.Soap12;
96 }
97
98 return soapVersion;
99 }
100
101 public static String getSoapAction( SoapVersion soapVersion, StringToStringMap headers )
102 {
103 String soapAction = null;
104 String contentType = headers.get( "Content-Type" );
105
106 if( soapVersion == SoapVersion.Soap11 )
107 {
108 soapAction = headers.get( "SOAPAction" );
109 }
110 else if( soapVersion == SoapVersion.Soap12 )
111 {
112 int ix = contentType.indexOf( "action=" );
113 if( ix > 0 )
114 {
115 int endIx = contentType.indexOf( ';', ix );
116 soapAction = endIx == -1 ? contentType.substring( ix + 7 ) : contentType.substring( ix + 7, endIx );
117 }
118 }
119
120 soapAction = StringUtils.unquote( soapAction );
121
122 return soapAction;
123 }
124
125 public static XmlObject getBodyElement(XmlObject messageObject, SoapVersion soapVersion ) throws XmlException
126 {
127 XmlObject[] envelope = messageObject.selectChildren( soapVersion.getEnvelopeQName() );
128 if( envelope.length != 1 )
129 throw new XmlException( "Missing/Invalid SOAP Envelope, expecting [" + soapVersion.getEnvelopeQName() + "]" );
130
131 XmlObject[] body = envelope[0].selectChildren( soapVersion.getBodyQName() );
132 if( body.length != 1 )
133 throw new XmlException( "Missing/Invalid SOAP Body, expecting [" + soapVersion.getBodyQName() + "]" );
134
135 return body[0];
136 }
137
138 public static XmlObject getHeaderElement(XmlObject messageObject, SoapVersion soapVersion, boolean create ) throws XmlException
139 {
140 XmlObject[] envelope = messageObject.selectChildren( soapVersion.getEnvelopeQName() );
141 if( envelope.length != 1 )
142 throw new XmlException( "Missing/Invalid SOAP Envelope, expecting [" + soapVersion.getEnvelopeQName() + "]" );
143
144 QName headerQName = soapVersion.getHeaderQName();
145 XmlObject[] header = envelope[0].selectChildren( headerQName );
146 if( header.length == 0 && create )
147 {
148 Element elm = (Element) envelope[0].getDomNode();
149 Element headerElement = elm.getOwnerDocument().createElementNS(
150 headerQName.getNamespaceURI(), headerQName.getLocalPart() );
151
152 elm.insertBefore(headerElement, elm.getFirstChild());
153
154 header = envelope[0].selectChildren( headerQName );
155 }
156
157 return header.length == 0 ? null : header[0];
158 }
159
160
161 public static XmlObject getContentElement( XmlObject messageObject, SoapVersion soapVersion ) throws XmlException
162 {
163 XmlObject bodyElement = SoapUtils.getBodyElement(messageObject, soapVersion);
164 if( bodyElement != null )
165 {
166 XmlCursor cursor = bodyElement.newCursor();
167
168 try
169 {
170 if( cursor.toFirstChild() )
171 {
172 while( !cursor.isContainer() )
173 cursor.toNextSibling();
174
175 if( cursor.isContainer() )
176 {
177 return cursor.getObject();
178 }
179 }
180 }
181 catch( Exception e )
182 {
183 SoapUI.logError( e );
184 }
185 finally
186 {
187 cursor.dispose();
188 }
189 }
190
191 return null;
192 }
193
194 @SuppressWarnings("unchecked")
195 public static WsdlOperation findOperationForRequest( SoapVersion soapVersion, String soapAction, XmlObject requestContent,
196 List<WsdlOperation> operations, boolean requireSoapVersionMatch, boolean requireSoapActionMatch ) throws XmlException, DispatchException, Exception
197 {
198 XmlObject contentElm = getContentElement( requestContent, soapVersion );
199 if( contentElm == null )
200 throw new DispatchException( "Missing content element in body" );
201
202 QName contentQName = XmlUtils.getQName( contentElm.getDomNode() );
203 NodeList contentChildNodes = null;
204
205 for( int c = 0; c < operations.size(); c++ )
206 {
207 WsdlOperation wsdlOperation = operations.get( c );
208 String action = wsdlOperation.getAction();
209
210
211 if( !requireSoapActionMatch || (
212 ( soapAction == null && wsdlOperation.getAction() == null ) ||
213 ( action != null && action.equals( soapAction ))
214 ))
215 {
216 QName qname = wsdlOperation.getRequestBodyElementQName();
217
218 if( !contentQName.equals( qname ) )
219 continue;
220
221 SoapVersion ifaceSoapVersion = wsdlOperation.getInterface().getSoapVersion();
222
223 if( requireSoapVersionMatch && ifaceSoapVersion != soapVersion )
224 {
225 continue;
226 }
227
228
229 if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_DOCUMENT ) )
230 {
231
232 return wsdlOperation;
233 }
234 else if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_RPC ) )
235 {
236 BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
237 Message message = bindingOperation.getOperation().getInput().getMessage();
238 List<Part> parts = message.getOrderedParts( null );
239
240 if( contentChildNodes == null )
241 contentChildNodes = XmlUtils.getChildElements( ( Element ) contentElm.getDomNode() );
242
243 int i = 0;
244
245 if( parts.size() > 0 )
246 {
247 for( int x = 0; x < parts.size(); x++ )
248 {
249 if( WsdlUtils.isAttachmentInputPart( parts.get( x ), bindingOperation ) ||
250 WsdlUtils.isHeaderInputPart( parts.get( x ), message, bindingOperation ))
251 {
252 parts.remove( x );
253 x--;
254 }
255 }
256
257 for( ; i < contentChildNodes.getLength() && !parts.isEmpty(); i++ )
258 {
259 Node item = contentChildNodes.item( i );
260 if( item.getNodeType() != Node.ELEMENT_NODE )
261 continue;
262
263 int j = 0;
264 while( ( j < parts.size() ) && ( !item.getNodeName().equals( parts.get( j ).getName() ) ) )
265 {
266 j++;
267 }
268
269 if( j == parts.size() )
270 break;
271
272 parts.remove( j );
273 }
274 }
275
276
277 if( i == contentChildNodes.getLength() && parts.isEmpty() )
278 {
279 return wsdlOperation;
280 }
281 }
282 }
283 }
284
285 throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element ["
286 + contentQName + "] with SOAP Version [" + soapVersion + "]" );
287 }
288
289 public static String removeEmptySoapHeaders( String content, SoapVersion soapVersion ) throws XmlException
290 {
291 XmlObject xmlObject = XmlObject.Factory.parse( content );
292 XmlObject[] selectPath = xmlObject.selectPath( "declare namespace soap='" + soapVersion.getEnvelopeNamespace() + "';/soap:Envelope/soap:Header" );
293 if( selectPath.length > 0 )
294 {
295 Node domNode = selectPath[0].getDomNode();
296 if( !domNode.hasChildNodes() && !domNode.hasAttributes())
297 {
298 domNode.getParentNode().removeChild( domNode );
299 return xmlObject.xmlText();
300 }
301 }
302
303 return content;
304 }
305
306 public static SoapVersion deduceSoapVersion(String requestContentType, String requestContent)
307 {
308 try
309 {
310 return deduceSoapVersion(requestContentType, XmlObject.Factory.parse(requestContent));
311 }
312 catch (XmlException e)
313 {
314 return deduceSoapVersion(requestContentType,(XmlObject)null);
315 }
316 }
317 }