1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers.http;
12
13 import org.mule.impl.MuleMessage;
14 import org.mule.impl.message.ExceptionPayload;
15 import org.mule.providers.AbstractMessageDispatcher;
16 import org.mule.providers.http.i18n.HttpMessages;
17 import org.mule.providers.http.transformers.HttpClientMethodResponseToObject;
18 import org.mule.providers.http.transformers.ObjectToHttpClientMethodRequest;
19 import org.mule.providers.streaming.StreamMessageAdapter;
20 import org.mule.umo.UMOEvent;
21 import org.mule.umo.UMOMessage;
22 import org.mule.umo.endpoint.UMOImmutableEndpoint;
23 import org.mule.umo.provider.DispatchException;
24 import org.mule.umo.provider.ReceiveException;
25 import org.mule.umo.provider.UMOMessageAdapter;
26 import org.mule.umo.provider.UMOStreamMessageAdapter;
27 import org.mule.umo.transformer.TransformerException;
28 import org.mule.umo.transformer.UMOTransformer;
29 import org.mule.util.StringUtils;
30
31 import java.io.IOException;
32 import java.io.OutputStream;
33 import java.net.URI;
34 import java.net.URISyntaxException;
35 import java.util.Iterator;
36 import java.util.Map;
37 import java.util.Properties;
38
39 import org.apache.commons.codec.binary.Base64;
40 import org.apache.commons.httpclient.Cookie;
41 import org.apache.commons.httpclient.Header;
42 import org.apache.commons.httpclient.HostConfiguration;
43 import org.apache.commons.httpclient.HttpClient;
44 import org.apache.commons.httpclient.HttpMethod;
45 import org.apache.commons.httpclient.HttpState;
46 import org.apache.commons.httpclient.HttpStatus;
47 import org.apache.commons.httpclient.UsernamePasswordCredentials;
48 import org.apache.commons.httpclient.auth.AuthScope;
49 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
50 import org.apache.commons.httpclient.methods.GetMethod;
51 import org.apache.commons.httpclient.methods.PostMethod;
52 import org.apache.commons.httpclient.methods.RequestEntity;
53 import org.apache.commons.httpclient.params.HttpMethodParams;
54 import org.apache.commons.httpclient.protocol.Protocol;
55 import org.apache.commons.io.IOUtils;
56
57
58
59
60 public class HttpClientMessageDispatcher extends AbstractMessageDispatcher
61 {
62 private final HttpConnector connector;
63 private volatile HttpClient client = null;
64 private final UMOTransformer receiveTransformer;
65
66 public HttpClientMessageDispatcher(UMOImmutableEndpoint endpoint)
67 {
68 super(endpoint);
69 this.connector = (HttpConnector) endpoint.getConnector();
70 this.receiveTransformer = new HttpClientMethodResponseToObject();
71 }
72
73 protected void doConnect() throws Exception
74 {
75 if (client == null)
76 {
77 HttpState state = new HttpState();
78
79 if (connector.getProxyUsername() != null)
80 {
81 state.setProxyCredentials(new AuthScope(null, -1, null, null),
82 new UsernamePasswordCredentials(connector.getProxyUsername(),
83 connector.getProxyPassword()));
84 }
85
86 client = new HttpClient();
87 client.setState(state);
88 client.setHttpConnectionManager(connector.getClientConnectionManager());
89
90
91
92
93
94
95
96
97
98
99
100
101
102 }
103
104 }
105
106 protected void doDisconnect() throws Exception
107 {
108 client = null;
109 }
110
111 protected void doDispatch(UMOEvent event) throws Exception
112 {
113 HttpMethod httpMethod = getMethod(event);
114 execute(event, httpMethod, true);
115 if (httpMethod.getStatusCode() >= 400)
116 {
117 logger.error(httpMethod.getResponseBodyAsString());
118 throw new DispatchException(event.getMessage(), event.getEndpoint(), new Exception(
119 "Http call returned a status of: " + httpMethod.getStatusCode() + " "
120 + httpMethod.getStatusText()));
121 }
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135 protected UMOMessage doReceive(long timeout) throws Exception
136 {
137 HttpMethod httpMethod = new GetMethod(endpoint.getEndpointURI().getAddress());
138 httpMethod.setDoAuthentication(true);
139 if (endpoint.getEndpointURI().getUserInfo() != null
140 && endpoint.getProperty(HttpConstants.HEADER_AUTHORIZATION) == null)
141 {
142
143 StringBuffer header = new StringBuffer(128);
144 header.append("Basic ");
145 header.append(new String(Base64.encodeBase64(endpoint.getEndpointURI().getUserInfo().getBytes(
146 endpoint.getEncoding()))));
147 httpMethod.addRequestHeader(HttpConstants.HEADER_AUTHORIZATION, header.toString());
148 }
149 try
150 {
151 HttpClient client = new HttpClient();
152 client.executeMethod(httpMethod);
153
154 if (httpMethod.getStatusCode() == HttpStatus.SC_OK)
155 {
156 return (UMOMessage) receiveTransformer.transform(httpMethod);
157 }
158 else
159 {
160 throw new ReceiveException(
161 HttpMessages.requestFailedWithStatus(httpMethod.getStatusLine().toString()),
162 endpoint, timeout);
163 }
164 }
165 catch (ReceiveException e)
166 {
167 throw e;
168 }
169 catch (Exception e)
170 {
171 throw new ReceiveException(endpoint, timeout, e);
172 }
173 finally
174 {
175 httpMethod.releaseConnection();
176 }
177 }
178
179 protected HttpMethod execute(UMOEvent event, HttpMethod httpMethod, boolean closeConnection)
180 throws Exception
181 {
182
183 try
184 {
185 URI uri = event.getEndpoint().getEndpointURI().getUri();
186
187 this.processCookies(event);
188
189
190 client.executeMethod(getHostConfig(uri), httpMethod);
191
192 return httpMethod;
193 }
194 catch (IOException e)
195 {
196
197 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
198 }
199 catch (Exception e)
200 {
201 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
202 }
203 finally
204 {
205 if (httpMethod != null && closeConnection)
206 {
207 httpMethod.releaseConnection();
208 }
209 }
210 }
211
212 protected void processCookies(UMOEvent event)
213 {
214 UMOMessage msg = event.getMessage();
215 Cookie[] cookies = (Cookie[]) msg.removeProperty(HttpConnector.HTTP_COOKIES_PROPERTY);
216 if (cookies != null && cookies.length > 0)
217 {
218 String policy = (String) msg.removeProperty(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY);
219 client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
220 client.getState().addCookies(cookies);
221 }
222 }
223
224 protected HttpMethod getMethod(UMOEvent event) throws TransformerException
225 {
226 UMOMessage msg = event.getMessage();
227 String method = msg.getStringProperty(HttpConnector.HTTP_METHOD_PROPERTY, HttpConstants.METHOD_POST);
228 URI uri = event.getEndpoint().getEndpointURI().getUri();
229 HttpMethod httpMethod;
230 Object body = event.getTransformedMessage();
231
232 if (body instanceof HttpMethod)
233 {
234 httpMethod = (HttpMethod)body;
235 }
236 else if (HttpConstants.METHOD_GET.equalsIgnoreCase(method))
237 {
238 httpMethod = new GetMethod(uri.toString());
239 }
240 else
241 {
242 PostMethod postMethod = new PostMethod(uri.toString());
243
244 if (body instanceof String)
245 {
246 ObjectToHttpClientMethodRequest trans = new ObjectToHttpClientMethodRequest();
247 httpMethod = (HttpMethod)trans.transform(body.toString());
248 }
249 else if (body instanceof UMOStreamMessageAdapter)
250 {
251 UMOStreamMessageAdapter sma = (UMOStreamMessageAdapter)body;
252 Map headers = sma.getOutputHandler().getHeaders(event);
253 for (Iterator iterator = headers.entrySet().iterator(); iterator.hasNext();)
254 {
255 Map.Entry entry = (Map.Entry)iterator.next();
256 postMethod.addRequestHeader((String)entry.getKey(), (String)entry.getValue());
257 }
258 postMethod.setRequestEntity(new StreamPayloadRequestEntity((StreamMessageAdapter)body, event));
259 postMethod.setContentChunked(true);
260 httpMethod = postMethod;
261 }
262 else
263 {
264 byte[] buffer = event.getTransformedMessageAsBytes();
265 postMethod.setRequestEntity(new ByteArrayRequestEntity(buffer, event.getEncoding()));
266 httpMethod = postMethod;
267 }
268
269 }
270 httpMethod.setDoAuthentication(true);
271 if (event.getCredentials() != null)
272 {
273 String authScopeHost = msg.getStringProperty("http.auth.scope.host", null);
274 int authScopePort = msg.getIntProperty("http.auth.scope.port", -1);
275 String authScopeRealm = msg.getStringProperty("http.auth.scope.realm", null);
276 String authScopeScheme = msg.getStringProperty("http.auth.scope.scheme", null);
277 client.getState().setCredentials(
278 new AuthScope(authScopeHost, authScopePort, authScopeRealm, authScopeScheme),
279 new UsernamePasswordCredentials(event.getCredentials().getUsername(), new String(
280 event.getCredentials().getPassword())));
281 client.getParams().setAuthenticationPreemptive(true);
282 }
283 else
284 {
285
286 client.getParams().setAuthenticationPreemptive(false);
287 }
288 return httpMethod;
289 }
290
291
292
293
294
295
296 protected UMOMessage doSend(UMOEvent event) throws Exception
297 {
298 HttpMethod httpMethod = getMethod(event);
299 httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new MuleHttpMethodRetryHandler());
300
301 httpMethod = execute(event, httpMethod, false);
302
303 try
304 {
305 Properties h = new Properties();
306 Header[] headers = httpMethod.getResponseHeaders();
307 for (int i = 0; i < headers.length; i++)
308 {
309 h.setProperty(headers[i].getName(), headers[i].getValue());
310 }
311
312 String status = String.valueOf(httpMethod.getStatusCode());
313
314 h.setProperty(HttpConnector.HTTP_STATUS_PROPERTY, status);
315 if (logger.isDebugEnabled())
316 {
317 logger.debug("Http response is: " + status);
318 }
319 ExceptionPayload ep = null;
320 if (httpMethod.getStatusCode() >= 400)
321 {
322 ep = new ExceptionPayload(new DispatchException(event.getMessage(), event.getEndpoint(),
323 new Exception("Http call returned a status of: " + httpMethod.getStatusCode() + " "
324 + httpMethod.getStatusText())));
325 }
326 UMOMessage m;
327
328 Header header = httpMethod.getResponseHeader(HttpConstants.HEADER_CONTENT_TYPE);
329 if ((header != null) && event.isStreaming())
330 {
331 HttpStreamMessageAdapter sp = (HttpStreamMessageAdapter)connector.getStreamMessageAdapter(
332 httpMethod.getResponseBodyAsStream(), null);
333 sp.setHttpMethod(httpMethod);
334 m = new MuleMessage(sp, h);
335 }
336 else
337 {
338 Object body = IOUtils.toByteArray(httpMethod.getResponseBodyAsStream());
339 if (body == null)
340 {
341 body = StringUtils.EMPTY;
342 }
343 UMOMessageAdapter adapter = connector.getMessageAdapter(new Object[]{body, h});
344 m = new MuleMessage(adapter);
345 }
346 m.setExceptionPayload(ep);
347 return m;
348 }
349 catch (Exception e)
350 {
351 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
352 }
353 finally
354 {
355 if (httpMethod != null && !event.isStreaming())
356 {
357 httpMethod.releaseConnection();
358 }
359 }
360 }
361
362 protected HostConfiguration getHostConfig(URI uri) throws URISyntaxException
363 {
364 Protocol protocol = Protocol.getProtocol(uri.getScheme().toLowerCase());
365
366 String host = uri.getHost();
367 int port = uri.getPort();
368 HostConfiguration config = new HostConfiguration();
369 config.setHost(host, port, protocol);
370 if (StringUtils.isNotBlank(connector.getProxyHostname()))
371 {
372
373 config.setProxy(connector.getProxyHostname(), connector.getProxyPort());
374 }
375 return config;
376 }
377
378 protected void doDispose()
379 {
380
381 }
382
383 private class StreamPayloadRequestEntity implements RequestEntity
384 {
385 private UMOStreamMessageAdapter messageAdapter;
386 private UMOEvent event;
387
388 public StreamPayloadRequestEntity(UMOStreamMessageAdapter messageAdapter, UMOEvent event)
389 {
390 this.messageAdapter = messageAdapter;
391 this.event = event;
392 }
393
394 public boolean isRepeatable()
395 {
396 return true;
397 }
398
399 public void writeRequest(OutputStream outputStream) throws IOException
400 {
401 messageAdapter.getOutputHandler().write(event, outputStream);
402 }
403
404 public long getContentLength()
405 {
406 return -1L;
407 }
408
409 public String getContentType()
410 {
411 return event.getMessage().getStringProperty(HttpConstants.HEADER_CONTENT_TYPE, null);
412 }
413 }
414
415 }