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