View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
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  		// check manually before resource intensive xpath
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 				// matches soapAction?
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 					// check content
196 					if( wsdlOperation.getStyle().equals( WsdlOperation.STYLE_DOCUMENT ) )
197 					{
198 						// matches!
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 						// match?
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 }