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.submit.transports.http;
14  
15  import java.net.InetAddress;
16  import java.util.ArrayList;
17  import java.util.List;
18  
19  import javax.activation.DataHandler;
20  import javax.mail.MessagingException;
21  import javax.mail.internet.MimeBodyPart;
22  import javax.mail.internet.MimeMessage;
23  import javax.mail.internet.MimeMultipart;
24  import javax.mail.internet.PreencodedMimeBodyPart;
25  
26  import org.apache.commons.httpclient.Header;
27  import org.apache.commons.httpclient.HostConfiguration;
28  import org.apache.commons.httpclient.HttpClient;
29  import org.apache.commons.httpclient.HttpState;
30  import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
31  import org.apache.log4j.Logger;
32  
33  import com.eviware.soapui.SoapUI;
34  import com.eviware.soapui.impl.wsdl.WsdlOperation;
35  import com.eviware.soapui.impl.wsdl.WsdlRequest;
36  import com.eviware.soapui.impl.wsdl.submit.RequestFilter;
37  import com.eviware.soapui.impl.wsdl.support.MessageXmlObject;
38  import com.eviware.soapui.impl.wsdl.support.MessageXmlPart;
39  import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
40  import com.eviware.soapui.model.iface.Response;
41  import com.eviware.soapui.model.iface.SubmitContext;
42  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
43  import com.eviware.soapui.model.settings.Settings;
44  import com.eviware.soapui.settings.HttpSettings;
45  import com.eviware.soapui.support.StringUtils;
46  import com.eviware.soapui.support.types.StringToStringMap;
47  
48  /***
49   * HTTP transport that uses HttpClient to send/receive SOAP messages
50   * 
51   * @author Ole.Matzura
52   */
53  
54  public class HttpClientRequestTransport implements BaseHttpRequestTransport
55  {
56  	private List<RequestFilter> filters = new ArrayList<RequestFilter>();
57  	private final static Logger log = Logger.getLogger(HttpClientRequestTransport.class);
58  	
59  	public HttpClientRequestTransport()
60  	{
61  		for( RequestFilter filter : SoapUI.getListenerRegistry().getListeners( RequestFilter.class ))
62  		{
63  			addRequestFilter( filter );
64  		}
65  	}
66  	
67  	public void addRequestFilter(RequestFilter filter)
68  	{
69  		filters.add( filter );
70  	}
71  
72  	public void removeRequestFilter(RequestFilter filter)
73  	{
74  		filters.remove( filter );
75  	}
76  
77  	public void abortRequest( SubmitContext submitContext )
78  	{
79  		TimeablePostMethod postMethod = (TimeablePostMethod) submitContext.getProperty( POST_METHOD );
80  		if( postMethod != null )
81  			postMethod.abort();
82  	}
83  
84  	public Response sendRequest( SubmitContext submitContext, WsdlRequest wsdlRequest ) throws Exception
85  	{
86  		HttpClient httpClient = HttpClientSupport.getHttpClient();
87  		TimeablePostMethod postMethod = new TimeablePostMethod();
88  		boolean createdState = false;
89  		
90  		HttpState httpState = (HttpState) submitContext.getProperty(SubmitContext.HTTP_STATE_PROPERTY);
91  		if( httpState == null )
92  		{
93  		   httpState = new HttpState();
94  		   submitContext.setProperty( SubmitContext.HTTP_STATE_PROPERTY, httpState );
95  		   createdState = true;
96  		}
97  		
98  		HostConfiguration hostConfiguration = new HostConfiguration();
99  
100 		String localAddress = System.getProperty( "soapui.bind.address", wsdlRequest.getBindAddress() );
101 		if( localAddress == null || localAddress.trim().length() == 0 )
102 			localAddress = SoapUI.getSettings().getString( HttpSettings.BIND_ADDRESS, null );
103 		
104 		if( localAddress != null && localAddress.trim().length() > 0 )
105 		{
106 			try
107 			{
108 				hostConfiguration.setLocalAddress( InetAddress.getByName( localAddress ));
109 			}
110 			catch( Exception e )
111 			{
112 				SoapUI.logError( e );
113 			}
114 		}
115 		
116 		submitContext.setProperty( POST_METHOD, postMethod );
117 		submitContext.setProperty( HTTP_CLIENT, httpClient );
118 		submitContext.setProperty( REQUEST_CONTENT, wsdlRequest.getRequestContent() );
119 		submitContext.setProperty( HOST_CONFIGURATION, hostConfiguration );
120 		submitContext.setProperty( WSDL_REQUEST, wsdlRequest );
121 		
122 		for( RequestFilter filter : filters )
123 		{
124 			filter.filterRequest( submitContext, wsdlRequest );
125 		}
126 		
127 		Response response = null;
128 		
129 		try
130 		{			
131 			Settings settings = wsdlRequest.getSettings();
132 
133 			// get request content
134 			String requestContent = (String) submitContext.getProperty(REQUEST_CONTENT);
135 
136 			// init
137 			requestContent = initRequest(wsdlRequest, postMethod, requestContent);
138 			
139 			//	custom http headers last so they can be overridden
140 			StringToStringMap headers = wsdlRequest.getRequestHeaders();
141 			for( String header : headers.keySet() )
142 			{
143 				String headerValue = headers.get( header );
144 				headerValue = PropertyExpansionUtils.expandProperties( submitContext, headerValue );
145 				postMethod.setRequestHeader( header, headerValue );
146 			}
147 			
148 			//	include request time?
149 			if (settings.getBoolean(HttpSettings.INCLUDE_REQUEST_IN_TIME_TAKEN))
150 				postMethod.initStartTime();
151 			
152 			//	do request
153 			httpClient.executeMethod(hostConfiguration, postMethod, httpState);
154 			
155 			Header responseContentTypeHeader = postMethod.getResponseHeader( "Content-Type" );
156 			
157 			if( !settings.getBoolean( WsdlRequest.INLINE_RESPONSE_ATTACHMENTS ) && 
158 				 responseContentTypeHeader != null && 
159 				 responseContentTypeHeader.getValue().toUpperCase().startsWith( "MULTIPART" ))
160 			{
161 				response = new MimeMessageResponse( wsdlRequest, postMethod, requestContent, submitContext );
162 			}
163 			else
164 			{
165 				response = new SinglePartHttpResponse( wsdlRequest, postMethod, requestContent, submitContext );
166 			}
167 			
168 			return response;
169 		}
170 		finally
171 		{
172 			for( RequestFilter filter : filters )
173 			{
174 				filter.afterRequest( submitContext, response );
175 			}
176 			
177 			if (postMethod != null)
178 			{
179 				postMethod.releaseConnection();
180 			}
181 			else log.error( "PostMethod is null");
182 			
183 			if( createdState )
184 				submitContext.setProperty( SubmitContext.HTTP_STATE_PROPERTY, null );
185 		}		
186 	}
187 
188 	private String initRequest(WsdlRequest wsdlRequest, TimeablePostMethod postMethod, String requestContent) throws Exception
189 	{
190 		MimeMultipart mp = null;
191 		
192 		StringToStringMap contentIds = new StringToStringMap();
193 		boolean isXOP = wsdlRequest.isMtomEnabled() && wsdlRequest.isForceMtom();
194 		
195 		// preprocess only if neccessary
196 		if( wsdlRequest.isMtomEnabled() || wsdlRequest.isInlineFilesEnabled() || wsdlRequest.getAttachmentCount() > 0 )
197 		{
198 			try
199 			{
200 				mp = new MimeMultipart();
201 				
202 				MessageXmlObject requestXmlObject = new MessageXmlObject(( WsdlOperation ) wsdlRequest.getOperation(), 
203 							requestContent, true);
204 				MessageXmlPart[] requestParts = requestXmlObject.getMessageParts();
205 				for (MessageXmlPart requestPart : requestParts)
206 				{
207 					if (AttachmentUtils.prepareMessagePart(wsdlRequest, mp, requestPart, contentIds))
208 						isXOP = true;
209 				}
210 				requestContent = requestXmlObject.getMessageContent();
211 			}
212 			catch (Exception e)
213 			{
214 				log.warn( "Failed to process inline/MTOM attachments; " + e );
215 			}			
216 		}
217 		
218 		// non-multipart request?
219 		if( !isXOP && (mp == null || mp.getCount() == 0 ) && wsdlRequest.getAttachmentCount() == 0 )
220 		{
221 			String encoding = StringUtils.unquote( wsdlRequest.getEncoding());
222 			byte[] content = encoding == null ? requestContent.getBytes() : requestContent.getBytes(encoding);
223 			postMethod.setRequestEntity(new ByteArrayRequestEntity(content));
224 		}
225 		else
226 		{
227 			// make sure..
228 			if( mp == null )
229 				mp = new MimeMultipart();
230 			
231 			// init root part
232 			initRootPart(wsdlRequest, requestContent, mp, isXOP);
233 			
234 			// init mimeparts
235 			AttachmentUtils.addMimeParts(wsdlRequest, mp, contentIds);
236 			
237 			// create request message
238 			MimeMessage message = new MimeMessage( AttachmentUtils.JAVAMAIL_SESSION );
239 			message.setContent( mp );
240 			message.saveChanges();
241 			MimeMessageRequestEntity mimeMessageRequestEntity = new MimeMessageRequestEntity( message, isXOP, wsdlRequest );
242 			postMethod.setRequestEntity( mimeMessageRequestEntity );
243 			postMethod.setRequestHeader( "Content-Type", mimeMessageRequestEntity.getContentType() );
244 			postMethod.setRequestHeader( "MIME-Version", "1.0" );
245 		}
246 		
247 		return requestContent;
248 	}
249 
250 	/***
251 	 * Creates root BodyPart containing message
252 	 */
253 	
254 	private void initRootPart(WsdlRequest wsdlRequest, String requestContent, MimeMultipart mp, boolean isXOP) throws MessagingException
255 	{
256 		MimeBodyPart rootPart = new PreencodedMimeBodyPart( "8bit" );
257 		rootPart.setContentID( AttachmentUtils.ROOTPART_SOAPUI_ORG );
258 		mp.addBodyPart( rootPart, 0 );
259 		
260 		DataHandler dataHandler = new DataHandler( new WsdlRequestDataSource( wsdlRequest, requestContent, isXOP ) );
261 		rootPart.setDataHandler( dataHandler);
262 	}
263 	
264 	
265 }