1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.http;
12
13 import org.mule.DefaultMuleMessage;
14 import org.mule.api.MuleEvent;
15 import org.mule.api.MuleMessage;
16 import org.mule.api.endpoint.OutboundEndpoint;
17 import org.mule.api.transformer.Transformer;
18 import org.mule.api.transformer.TransformerException;
19 import org.mule.api.transport.DispatchException;
20 import org.mule.api.transport.OutputHandler;
21 import org.mule.message.DefaultExceptionPayload;
22 import org.mule.transport.AbstractMessageDispatcher;
23 import org.mule.transport.http.transformers.ObjectToHttpClientMethodRequest;
24 import org.mule.util.StringUtils;
25
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.net.URI;
29 import java.net.URISyntaxException;
30 import java.util.Iterator;
31 import java.util.Map;
32
33 import org.apache.commons.httpclient.Cookie;
34 import org.apache.commons.httpclient.Header;
35 import org.apache.commons.httpclient.HostConfiguration;
36 import org.apache.commons.httpclient.HttpClient;
37 import org.apache.commons.httpclient.HttpMethod;
38 import org.apache.commons.httpclient.cookie.CookiePolicy;
39 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
40 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
41 import org.apache.commons.httpclient.params.HttpMethodParams;
42 import org.apache.commons.httpclient.protocol.Protocol;
43
44
45
46
47 public class HttpClientMessageDispatcher extends AbstractMessageDispatcher
48 {
49
50
51
52 public static final int ERROR_STATUS_CODE_RANGE_START = 400;
53 private final HttpConnector connector;
54 private volatile HttpClient client = null;
55 private final Transformer sendTransformer;
56
57 public HttpClientMessageDispatcher(OutboundEndpoint endpoint)
58 {
59 super(endpoint);
60 this.connector = (HttpConnector) endpoint.getConnector();
61 this.sendTransformer = new ObjectToHttpClientMethodRequest();
62 }
63
64 protected void doConnect() throws Exception
65 {
66 if (client == null)
67 {
68 client = connector.doClientConnect();
69 }
70 }
71
72 protected void doDisconnect() throws Exception
73 {
74 client = null;
75 }
76
77 protected void doDispatch(MuleEvent event) throws Exception
78 {
79 HttpMethod httpMethod = getMethod(event);
80 try
81 {
82 execute(event, httpMethod);
83
84 if (httpMethod.getStatusCode() >= ERROR_STATUS_CODE_RANGE_START)
85 {
86 logger.error(httpMethod.getResponseBodyAsString());
87 throw new DispatchException(event.getMessage(), event.getEndpoint(), new Exception(
88 "Http call returned a status of: " + httpMethod.getStatusCode() + " "
89 + httpMethod.getStatusText()));
90 }
91 }
92 finally
93 {
94 httpMethod.releaseConnection();
95 }
96 }
97
98 protected HttpMethod execute(MuleEvent event, HttpMethod httpMethod)
99 throws Exception
100 {
101
102 try
103 {
104 URI uri = event.getEndpoint().getEndpointURI().getUri();
105
106 this.processCookies(event);
107
108
109 client.executeMethod(getHostConfig(uri), httpMethod);
110
111 return httpMethod;
112 }
113 catch (IOException e)
114 {
115
116 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
117 }
118 catch (Exception e)
119 {
120 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
121 }
122
123 }
124
125 protected void processCookies(MuleEvent event)
126 {
127 MuleMessage msg = event.getMessage();
128 Object cookieObject = msg.removeProperty(HttpConnector.HTTP_COOKIES_PROPERTY);
129 if (cookieObject instanceof Cookie[])
130 {
131
132 Cookie[] cookies = (Cookie[]) cookieObject;
133 if (cookies != null && cookies.length > 0)
134 {
135 String policy = (String) msg.removeProperty(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY);
136 client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
137 client.getState().addCookies(cookies);
138 }
139 }
140 else if (cookieObject instanceof Map)
141 {
142
143 client.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
144
145 String host = this.getEndpoint().getEndpointURI().getHost();
146 String path = this.getEndpoint().getEndpointURI().getPath();
147 Map cookieMap = (Map) cookieObject;
148 Iterator keyIter = cookieMap.keySet().iterator();
149 while (keyIter.hasNext())
150 {
151 String key = (String) keyIter.next();
152 String value = (String) cookieMap.get(key);
153 Cookie cookie = new Cookie(host, key, value, path, null, false);
154 client.getState().addCookie(cookie);
155 }
156 }
157 else if (cookieObject != null)
158 {
159 throw new IllegalArgumentException("Invalid cookies " + cookieObject);
160 }
161 }
162
163 protected HttpMethod getMethod(MuleEvent event) throws TransformerException
164 {
165 MuleMessage msg = event.getMessage();
166 setPropertyFromEndpoint(event, msg, HttpConnector.HTTP_CUSTOM_HEADERS_MAP_PROPERTY);
167
168 HttpMethod httpMethod;
169 Object body = event.transformMessage();
170
171 if (body instanceof HttpMethod)
172 {
173 httpMethod = (HttpMethod)body;
174 }
175 else
176 {
177 httpMethod = (HttpMethod) sendTransformer.transform(msg);
178 }
179
180
181 return httpMethod;
182 }
183
184 protected void setPropertyFromEndpoint(MuleEvent event, MuleMessage msg, String prop)
185 {
186 Object o = msg.getProperty(prop, null);
187 if (o == null) {
188
189 o = event.getEndpoint().getProperty(prop);
190 if (o != null) {
191 msg.setProperty(prop, o);
192 }
193 }
194 }
195
196 protected HttpMethod createEntityMethod(MuleEvent event, Object body, EntityEnclosingMethod postMethod)
197 throws TransformerException
198 {
199 HttpMethod httpMethod;
200 if (body instanceof String)
201 {
202 ObjectToHttpClientMethodRequest trans = new ObjectToHttpClientMethodRequest();
203 httpMethod = (HttpMethod)trans.transform(body.toString());
204 }
205 else if (body instanceof byte[])
206 {
207 byte[] buffer = event.transformMessageToBytes();
208 postMethod.setRequestEntity(new ByteArrayRequestEntity(buffer, event.getEncoding()));
209 httpMethod = postMethod;
210 }
211 else
212 {
213 if (!(body instanceof OutputHandler))
214 {
215 body = event.transformMessage(OutputHandler.class);
216 }
217
218 OutputHandler outputHandler = (OutputHandler)body;
219 postMethod.setRequestEntity(new StreamPayloadRequestEntity(outputHandler, event));
220 postMethod.setContentChunked(true);
221 httpMethod = postMethod;
222 }
223
224 return httpMethod;
225 }
226
227
228
229
230
231
232 protected MuleMessage doSend(MuleEvent event) throws Exception
233 {
234 HttpMethod httpMethod = getMethod(event);
235 connector.setupClientAuthorization(event, httpMethod, client, endpoint);
236
237 httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new MuleHttpMethodRetryHandler());
238
239 Object body = null;
240 boolean releaseConn = false;
241 try
242 {
243 httpMethod = execute(event, httpMethod);
244
245 DefaultExceptionPayload ep = null;
246 if (httpMethod.getStatusCode() >= ERROR_STATUS_CODE_RANGE_START)
247 {
248 ep = new DefaultExceptionPayload(new DispatchException(event.getMessage(), event.getEndpoint(),
249 new Exception("Http call returned a status of: " + httpMethod.getStatusCode() + " "
250 + httpMethod.getStatusText())));
251 }
252
253
254 InputStream is = httpMethod.getResponseBodyAsStream();
255 if (is == null)
256 {
257 body = StringUtils.EMPTY;
258 releaseConn = true;
259 }
260 else
261 {
262 is = new ReleasingInputStream(is, httpMethod);
263 body = is;
264 }
265
266 Header[] headers = httpMethod.getResponseHeaders();
267 HttpMessageAdapter adapter = new HttpMessageAdapter(new Object[]{body, headers});
268
269 String status = String.valueOf(httpMethod.getStatusCode());
270
271 adapter.setProperty(HttpConnector.HTTP_STATUS_PROPERTY, status);
272 if (logger.isDebugEnabled())
273 {
274 logger.debug("Http response is: " + status);
275 }
276
277 MuleMessage m = new DefaultMuleMessage(adapter);
278
279 m.setExceptionPayload(ep);
280 return m;
281 }
282 catch (Exception e)
283 {
284 releaseConn = true;
285 if (e instanceof DispatchException)
286 {
287 throw (DispatchException) e;
288 }
289
290 throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
291 }
292 finally
293 {
294 if (releaseConn)
295 {
296 httpMethod.releaseConnection();
297 }
298 }
299 }
300
301 protected HostConfiguration getHostConfig(URI uri) throws URISyntaxException
302 {
303 Protocol protocol = Protocol.getProtocol(uri.getScheme().toLowerCase());
304
305 String host = uri.getHost();
306 int port = uri.getPort();
307 HostConfiguration config = new HostConfiguration();
308 config.setHost(host, port, protocol);
309 if (StringUtils.isNotBlank(connector.getProxyHostname()))
310 {
311
312 config.setProxy(connector.getProxyHostname(), connector.getProxyPort());
313 }
314 return config;
315 }
316
317 protected void doDispose()
318 {
319
320 }
321 }