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.DeleteMethod;
51 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
52 import org.apache.commons.httpclient.methods.GetMethod;
53 import org.apache.commons.httpclient.methods.HeadMethod;
54 import org.apache.commons.httpclient.methods.OptionsMethod;
55 import org.apache.commons.httpclient.methods.PostMethod;
56 import org.apache.commons.httpclient.methods.PutMethod;
57 import org.apache.commons.httpclient.methods.RequestEntity;
58 import org.apache.commons.httpclient.methods.TraceMethod;
59 import org.apache.commons.httpclient.params.HttpMethodParams;
60 import org.apache.commons.httpclient.protocol.Protocol;
61 import org.apache.commons.io.IOUtils;
62
63
64
65
66 public class HttpClientMessageDispatcher extends AbstractMessageDispatcher
67 {
68
69
70
71 public static final int ERROR_STATUS_CODE_RANGE_START = 400;
72 private final HttpConnector connector;
73 private volatile HttpClient client = null;
74 private final UMOTransformer receiveTransformer;
75
76 public HttpClientMessageDispatcher(UMOImmutableEndpoint endpoint)
77 {
78 super(endpoint);
79 this.connector = (HttpConnector) endpoint.getConnector();
80 this.receiveTransformer = new HttpClientMethodResponseToObject();
81 }
82
83 protected void doConnect() throws Exception
84 {
85 if (client == null)
86 {
87 HttpState state = new HttpState();
88
89 if (connector.getProxyUsername() != null)
90 {
91 state.setProxyCredentials(new AuthScope(null, -1, null, null),
92 new UsernamePasswordCredentials(connector.getProxyUsername(),
93 connector.getProxyPassword()));
94 }
95
96 client = new HttpClient();
97 client.setState(state);
98 client.setHttpConnectionManager(connector.getClientConnectionManager());
99 }
100
101 }
102
103 protected void doDisconnect() throws Exception
104 {
105 client = null;
106 }
107
108 protected void doDispatch(UMOEvent event) throws Exception
109 {
110 HttpMethod httpMethod = getMethod(event);
111 execute(event, httpMethod, true);
112 if (httpMethod.getStatusCode() >= ERROR_STATUS_CODE_RANGE_START)
113 {
114 logger.error(httpMethod.getResponseBodyAsString());
115 throw new DispatchException(event.getMessage(), event.getEndpoint(), new Exception(
116 "Http call returned a status of: " + httpMethod.getStatusCode() + " "
117 + httpMethod.getStatusText()));
118 }
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132 protected UMOMessage doReceive(long timeout) throws Exception
133 {
134 HttpMethod httpMethod = new GetMethod(endpoint.getEndpointURI().getAddress());
135 httpMethod.setDoAuthentication(true);
136 if (endpoint.getEndpointURI().getUserInfo() != null
137 && endpoint.getProperty(HttpConstants.HEADER_AUTHORIZATION) == null)
138 {
139
140 StringBuffer header = new StringBuffer(128);
141 header.append("Basic ");
142 header.append(new String(Base64.encodeBase64(endpoint.getEndpointURI().getUserInfo().getBytes(
143 endpoint.getEncoding()))));
144 httpMethod.addRequestHeader(HttpConstants.HEADER_AUTHORIZATION, header.toString());
145 }
146 try
147 {
148 HttpClient client = new HttpClient();
149 client.executeMethod(httpMethod);
150
151 if (httpMethod.getStatusCode() == HttpStatus.SC_OK)
152 {
153 return (UMOMessage) receiveTransformer.transform(httpMethod);
154 }
155 else
156 {
157 throw new ReceiveException(
158 HttpMessages.requestFailedWithStatus(httpMethod.getStatusLine().toString()),
159 endpoint, timeout);
160 }
161 }
162 catch (ReceiveException e)
163 {
164 throw e;
165 }
166 catch (Exception e)
167 {
168 throw new ReceiveException(endpoint, timeout, e);
169 }
170 finally
171 {
172 httpMethod.releaseConnection();
173 }
174 }
175
176 protected HttpMethod execute(UMOEvent event, HttpMethod httpMethod, boolean closeConnection)
177 throws Exception
178 {
179
180 try
181 {
182 URI uri = event.getEndpoint().getEndpointURI().getUri();
183
184 this.processCookies(event);
185
186
187 client.executeMethod(getHostConfig(uri), httpMethod);
188
189 return httpMethod;
190 }
191 catch (IOException e)
192 {
193
194 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
195 }
196 catch (Exception e)
197 {
198 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
199 }
200 finally
201 {
202 if (httpMethod != null && closeConnection)
203 {
204 httpMethod.releaseConnection();
205 }
206 }
207 }
208
209 protected void processCookies(UMOEvent event)
210 {
211 UMOMessage msg = event.getMessage();
212 Cookie[] cookies = (Cookie[]) msg.removeProperty(HttpConnector.HTTP_COOKIES_PROPERTY);
213 if (cookies != null && cookies.length > 0)
214 {
215 String policy = (String) msg.removeProperty(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY);
216 client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
217 client.getState().addCookies(cookies);
218 }
219 }
220
221 protected HttpMethod getMethod(UMOEvent event) throws TransformerException
222 {
223 UMOMessage msg = event.getMessage();
224 String method = msg.getStringProperty(HttpConnector.HTTP_METHOD_PROPERTY, HttpConstants.METHOD_POST);
225 URI uri = event.getEndpoint().getEndpointURI().getUri();
226 HttpMethod httpMethod;
227 Object body = event.getTransformedMessage();
228
229 if (body instanceof HttpMethod)
230 {
231 httpMethod = (HttpMethod)body;
232 }
233 else if (HttpConstants.METHOD_GET.equalsIgnoreCase(method))
234 {
235 httpMethod = new GetMethod(uri.toString());
236 }
237 else if (HttpConstants.METHOD_PUT.equalsIgnoreCase(method))
238 {
239 PutMethod postMethod = new PutMethod(uri.toString());
240
241 httpMethod = createEntityMethod(event, body, postMethod);
242 }
243 else if (HttpConstants.METHOD_POST.equalsIgnoreCase(method))
244 {
245 PostMethod postMethod = new PostMethod(uri.toString());
246
247 httpMethod = createEntityMethod(event, body, postMethod);
248 }
249 else if (HttpConstants.METHOD_DELETE.equalsIgnoreCase(method))
250 {
251 httpMethod = new DeleteMethod(uri.toString());
252 }
253 else if (HttpConstants.METHOD_HEAD.equalsIgnoreCase(method))
254 {
255 httpMethod = new HeadMethod(uri.toString());
256 }
257 else if (HttpConstants.METHOD_OPTIONS.equalsIgnoreCase(method))
258 {
259 httpMethod = new OptionsMethod(uri.toString());
260 }
261 else if (HttpConstants.METHOD_TRACE.equalsIgnoreCase(method))
262 {
263 httpMethod = new TraceMethod(uri.toString());
264 }
265 else
266 {
267 throw new TransformerException(HttpMessages.unsupportedMethod(method));
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 protected HttpMethod createEntityMethod(UMOEvent event, Object body, EntityEnclosingMethod postMethod)
292 throws TransformerException
293 {
294 HttpMethod httpMethod;
295 if (body instanceof String)
296 {
297 ObjectToHttpClientMethodRequest trans = new ObjectToHttpClientMethodRequest();
298 httpMethod = (HttpMethod)trans.transform(body.toString());
299 }
300 else if (body instanceof UMOStreamMessageAdapter)
301 {
302 UMOStreamMessageAdapter sma = (UMOStreamMessageAdapter)body;
303 Map headers = sma.getOutputHandler().getHeaders(event);
304 for (Iterator iterator = headers.entrySet().iterator(); iterator.hasNext();)
305 {
306 Map.Entry entry = (Map.Entry)iterator.next();
307 postMethod.addRequestHeader((String)entry.getKey(), (String)entry.getValue());
308 }
309 postMethod.setRequestEntity(new StreamPayloadRequestEntity((StreamMessageAdapter)body, event));
310 postMethod.setContentChunked(true);
311 httpMethod = postMethod;
312 }
313 else
314 {
315 byte[] buffer = event.getTransformedMessageAsBytes();
316 postMethod.setRequestEntity(new ByteArrayRequestEntity(buffer, event.getEncoding()));
317 httpMethod = postMethod;
318 }
319 return httpMethod;
320 }
321
322
323
324
325
326
327 protected UMOMessage doSend(UMOEvent event) throws Exception
328 {
329 HttpMethod httpMethod = getMethod(event);
330 httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new MuleHttpMethodRetryHandler());
331
332 httpMethod = execute(event, httpMethod, false);
333
334 try
335 {
336 Properties h = new Properties();
337 Header[] headers = httpMethod.getResponseHeaders();
338 for (int i = 0; i < headers.length; i++)
339 {
340 h.setProperty(headers[i].getName(), headers[i].getValue());
341 }
342
343 String status = String.valueOf(httpMethod.getStatusCode());
344
345 h.setProperty(HttpConnector.HTTP_STATUS_PROPERTY, status);
346 if (logger.isDebugEnabled())
347 {
348 logger.debug("Http response is: " + status);
349 }
350 ExceptionPayload ep = null;
351 if (httpMethod.getStatusCode() >= ERROR_STATUS_CODE_RANGE_START)
352 {
353 ep = new ExceptionPayload(new DispatchException(event.getMessage(), event.getEndpoint(),
354 new Exception("Http call returned a status of: " + httpMethod.getStatusCode() + " "
355 + httpMethod.getStatusText())));
356 }
357 UMOMessage m;
358
359 Header header = httpMethod.getResponseHeader(HttpConstants.HEADER_CONTENT_TYPE);
360 if ((header != null) && event.isStreaming())
361 {
362 HttpStreamMessageAdapter sp = (HttpStreamMessageAdapter)connector.getStreamMessageAdapter(
363 httpMethod.getResponseBodyAsStream(), null);
364 sp.setHttpMethod(httpMethod);
365 m = new MuleMessage(sp, h);
366 }
367 else
368 {
369 Object body = IOUtils.toByteArray(httpMethod.getResponseBodyAsStream());
370 if (body == null)
371 {
372 body = StringUtils.EMPTY;
373 }
374 UMOMessageAdapter adapter = connector.getMessageAdapter(new Object[]{body, h});
375 m = new MuleMessage(adapter);
376 }
377 m.setExceptionPayload(ep);
378 return m;
379 }
380 catch (Exception e)
381 {
382 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
383 }
384 finally
385 {
386 if (httpMethod != null && !event.isStreaming())
387 {
388 httpMethod.releaseConnection();
389 }
390 }
391 }
392
393 protected HostConfiguration getHostConfig(URI uri) throws URISyntaxException
394 {
395 Protocol protocol = Protocol.getProtocol(uri.getScheme().toLowerCase());
396
397 String host = uri.getHost();
398 int port = uri.getPort();
399 HostConfiguration config = new HostConfiguration();
400 config.setHost(host, port, protocol);
401 if (StringUtils.isNotBlank(connector.getProxyHostname()))
402 {
403
404 config.setProxy(connector.getProxyHostname(), connector.getProxyPort());
405 }
406 return config;
407 }
408
409 protected void doDispose()
410 {
411
412 }
413
414 protected class StreamPayloadRequestEntity implements RequestEntity
415 {
416 private UMOStreamMessageAdapter messageAdapter;
417 private UMOEvent event;
418
419 public StreamPayloadRequestEntity(UMOStreamMessageAdapter messageAdapter, UMOEvent event)
420 {
421 this.messageAdapter = messageAdapter;
422 this.event = event;
423 }
424
425 public boolean isRepeatable()
426 {
427 return true;
428 }
429
430 public void writeRequest(OutputStream outputStream) throws IOException
431 {
432 messageAdapter.getOutputHandler().write(event, outputStream);
433 }
434
435 public long getContentLength()
436 {
437 return -1L;
438 }
439
440 public String getContentType()
441 {
442 return event.getMessage().getStringProperty(HttpConstants.HEADER_CONTENT_TYPE, null);
443 }
444 }
445
446 }