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