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