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.Element;
26 import org.w3c.dom.Node;
27 import org.w3c.dom.NodeList;
28
29 import com.eviware.soapui.SoapUI;
30 import com.eviware.soapui.impl.wsdl.WsdlInterface;
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.Interface;
35 import com.eviware.soapui.support.StringUtils;
36 import com.eviware.soapui.support.types.StringToStringMap;
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 and/or override?
67 */
68
69 public static SoapVersion initSoapVersion( String contentType )
70 {
71 if( StringUtils.isNullOrEmpty( contentType ) )
72 return null;
73
74 SoapVersion soapVersion;
75
76 soapVersion = contentType.startsWith( SoapVersion.Soap11.getContentType() ) ? SoapVersion.Soap11 : null;
77 soapVersion = soapVersion == null && contentType.startsWith( SoapVersion.Soap12.getContentType() ) ? SoapVersion.Soap12 : soapVersion;
78 if( soapVersion == null && contentType.startsWith( "application/xop+xml" ))
79 {
80 if( contentType.indexOf( "type=\"" + SoapVersion.Soap11.getContentType() + "\"" ) > 0 )
81 soapVersion = SoapVersion.Soap11;
82 else if( contentType.indexOf( "type=\"" + SoapVersion.Soap12.getContentType() + "\"" ) > 0 )
83 soapVersion = SoapVersion.Soap12;
84 }
85
86 return soapVersion;
87 }
88
89 public static String getSoapAction( SoapVersion soapVersion, StringToStringMap headers )
90 {
91 String soapAction = null;
92 String contentType = headers.get( "Content-Type" );
93
94 if( soapVersion == SoapVersion.Soap11 )
95 {
96 soapAction = headers.get( "SOAPAction" );
97 }
98 else if( soapVersion == SoapVersion.Soap12 )
99 {
100 int ix = contentType.indexOf( "action=" );
101 if( ix > 0 )
102 {
103 int endIx = contentType.indexOf( ';', ix );
104 soapAction = endIx == -1 ? contentType.substring( ix + 7 ) : contentType.substring( ix + 7, endIx );
105 }
106 }
107
108 if( soapAction != null && soapAction.startsWith( "\"" ) && soapAction.endsWith( "\"" ) && soapAction.length() > 1)
109 soapAction = soapAction.substring( 1, soapAction.length()-1 );
110
111 return soapAction;
112 }
113
114 public static XmlObject getBodyElement(XmlObject messageObject, SoapVersion soapVersion ) throws XmlException
115 {
116 XmlObject[] envelope = messageObject.selectChildren( soapVersion.getEnvelopeQName() );
117 if( envelope.length != 1 )
118 throw new XmlException( "Missing/Invalid SOAP Envelope, expecting [" + soapVersion.getEnvelopeQName() + "]" );
119
120 XmlObject[] body = envelope[0].selectChildren( soapVersion.getBodyQName() );
121 if( body.length != 1 )
122 throw new XmlException( "Missing/Invalid SOAP Body, expecting [" + soapVersion.getBodyQName() + "]" );
123
124 return body[0];
125 }
126
127 public static XmlObject getContentElement( XmlObject messageObject, SoapVersion soapVersion ) throws XmlException
128 {
129 XmlObject bodyElement = SoapUtils.getBodyElement(messageObject, soapVersion);
130 if( bodyElement != null )
131 {
132 XmlCursor cursor = bodyElement.newCursor();
133
134 try
135 {
136 if( cursor.toFirstChild() )
137 {
138 while( !cursor.isContainer() )
139 cursor.toNextSibling();
140
141 if( cursor.isContainer() )
142 {
143 return cursor.getObject();
144 }
145 }
146 }
147 catch( Exception e )
148 {
149 SoapUI.logError( e );
150 }
151 finally
152 {
153 cursor.dispose();
154 }
155 }
156
157 return null;
158 }
159
160 public static WsdlOperation findOperationForRequest( SoapVersion soapVersion, String soapAction, XmlObject requestContent,
161 List<Interface> interfaces, boolean requireSoapVersionMatch ) throws XmlException, DispatchException, Exception
162 {
163 XmlObject contentElm = getContentElement( requestContent, soapVersion );
164 if( contentElm == null )
165 throw new DispatchException( "Missing content element in body" );
166
167 QName contentQName = XmlUtils.getQName( contentElm.getDomNode() );
168 NodeList contentChildNodes = null;
169
170 for( int w = 0; w < interfaces.size(); w++ )
171 {
172 WsdlInterface iface = ( WsdlInterface ) interfaces.get( w );
173 SoapVersion ifaceSoapVersion = iface.getSoapVersion();
174
175 for( int c = 0; c < iface.getOperationCount(); c++ )
176 {
177 WsdlOperation wsdlOperation = iface.getOperationAt( c );
178 String action = wsdlOperation.getAction();
179
180
181 if( ( soapAction == null && wsdlOperation.getAction() == null )
182 || ( action.equals( soapAction ) || ( wsdlOperation.getAction() != null && wsdlOperation
183 .getAction().equals( soapAction ) ) ) )
184 {
185 QName qname = wsdlOperation.getRequestBodyElementQName();
186
187 if( !qname.equals( contentQName ) )
188 continue;
189
190 if( requireSoapVersionMatch && ifaceSoapVersion != soapVersion )
191 {
192 continue;
193 }
194
195
196 if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_DOCUMENT ) )
197 {
198
199 return wsdlOperation;
200 }
201 else if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_RPC ) )
202 {
203 BindingOperation bindingOperation = wsdlOperation.getBindingOperation();
204 Message message = bindingOperation.getOperation().getInput().getMessage();
205 List<Part> parts = message.getOrderedParts( null );
206
207 if( contentChildNodes == null )
208 contentChildNodes = XmlUtils.getChildElements( ( Element ) contentElm.getDomNode() );
209
210 int i = 0;
211
212 if( parts.size() > 0 )
213 {
214 for( int x = 0; x < parts.size(); x++ )
215 {
216 if( WsdlUtils.isAttachmentInputPart( parts.get( x ), bindingOperation ) ||
217 WsdlUtils.isHeaderInputPart( parts.get( x ), message, bindingOperation ))
218 {
219 parts.remove( x );
220 x--;
221 }
222 }
223
224 for( ; i < contentChildNodes.getLength() && !parts.isEmpty(); i++ )
225 {
226 Node item = contentChildNodes.item( i );
227 if( item.getNodeType() != Node.ELEMENT_NODE )
228 continue;
229
230 int j = 0;
231 while( ( j < parts.size() ) && ( !item.getNodeName().equals( parts.get( j ).getName() ) ) )
232 {
233 j++;
234 }
235
236 if( j == parts.size() )
237 break;
238
239 parts.remove( j );
240 }
241 }
242
243
244 if( i == contentChildNodes.getLength() && parts.isEmpty() )
245 {
246 return wsdlOperation;
247 }
248 }
249 }
250 }
251 }
252
253 throw new DispatchException( "Missing operation for soapAction [" + soapAction + "] and body element ["
254 + contentQName + "] with SOAP Version [" + soapVersion + "]" );
255 }
256
257 public static String removeEmptySoapHeaders( String content, SoapVersion soapVersion ) throws XmlException
258 {
259 XmlObject xmlObject = XmlObject.Factory.parse( content );
260 XmlObject[] selectPath = xmlObject.selectPath( "declare namespace soap='" + soapVersion.getEnvelopeNamespace() + "';/soap:Envelope/soap:Header" );
261 if( selectPath.length > 0 )
262 {
263 Node domNode = selectPath[0].getDomNode();
264 if( !domNode.hasChildNodes() && !domNode.hasAttributes())
265 {
266 domNode.getParentNode().removeChild( domNode );
267 return xmlObject.xmlText();
268 }
269 }
270
271 return content;
272 }
273 }