1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.http.transformers;
12
13 import org.mule.RequestContext;
14 import org.mule.api.MuleEvent;
15 import org.mule.api.MuleMessage;
16 import org.mule.api.config.MuleProperties;
17 import org.mule.api.transformer.TransformerException;
18 import org.mule.api.transport.OutputHandler;
19 import org.mule.api.transport.PropertyScope;
20 import org.mule.message.ds.StringDataSource;
21 import org.mule.transformer.AbstractMessageTransformer;
22 import org.mule.transformer.types.DataTypeFactory;
23 import org.mule.transport.NullPayload;
24 import org.mule.transport.http.HttpConnector;
25 import org.mule.transport.http.HttpConstants;
26 import org.mule.transport.http.StreamPayloadRequestEntity;
27 import org.mule.transport.http.i18n.HttpMessages;
28 import org.mule.util.IOUtils;
29 import org.mule.util.ObjectUtils;
30 import org.mule.util.SerializationUtils;
31 import org.mule.util.StringUtils;
32
33 import java.io.InputStream;
34 import java.io.Serializable;
35 import java.io.UnsupportedEncodingException;
36 import java.net.URI;
37 import java.net.URISyntaxException;
38 import java.net.URLEncoder;
39 import java.util.Iterator;
40 import java.util.Map;
41
42 import javax.activation.DataHandler;
43 import javax.activation.FileDataSource;
44 import javax.activation.URLDataSource;
45
46 import org.apache.commons.httpclient.HttpMethod;
47 import org.apache.commons.httpclient.HttpVersion;
48 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
49 import org.apache.commons.httpclient.methods.DeleteMethod;
50 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
51 import org.apache.commons.httpclient.methods.GetMethod;
52 import org.apache.commons.httpclient.methods.HeadMethod;
53 import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
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.StringRequestEntity;
58 import org.apache.commons.httpclient.methods.TraceMethod;
59 import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource;
60 import org.apache.commons.httpclient.methods.multipart.FilePart;
61 import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
62 import org.apache.commons.httpclient.methods.multipart.Part;
63 import org.apache.commons.httpclient.methods.multipart.StringPart;
64 import org.apache.commons.httpclient.params.HttpMethodParams;
65
66
67
68
69
70 public class ObjectToHttpClientMethodRequest extends AbstractMessageTransformer
71 {
72 public ObjectToHttpClientMethodRequest()
73 {
74 setReturnDataType(DataTypeFactory.create(HttpMethod.class));
75 registerSourceType(DataTypeFactory.MULE_MESSAGE);
76 registerSourceType(DataTypeFactory.BYTE_ARRAY);
77 registerSourceType(DataTypeFactory.STRING);
78 registerSourceType(DataTypeFactory.INPUT_STREAM);
79 registerSourceType(DataTypeFactory.create(OutputHandler.class));
80 registerSourceType(DataTypeFactory.create(NullPayload.class));
81 }
82
83 @Override
84 public Object transformMessage(MuleMessage msg, String outputEncoding) throws TransformerException
85 {
86 String method = detectHttpMethod(msg);
87 try
88 {
89 HttpMethod httpMethod;
90
91 if (HttpConstants.METHOD_GET.equals(method))
92 {
93 httpMethod = createGetMethod(msg, outputEncoding);
94 }
95 else if (HttpConstants.METHOD_POST.equalsIgnoreCase(method))
96 {
97 httpMethod = createPostMethod(msg, outputEncoding);
98 }
99 else if (HttpConstants.METHOD_PUT.equalsIgnoreCase(method))
100 {
101 httpMethod = createPutMethod(msg, outputEncoding);
102 }
103 else if (HttpConstants.METHOD_DELETE.equalsIgnoreCase(method))
104 {
105 httpMethod = createDeleteMethod(msg);
106 }
107 else if (HttpConstants.METHOD_HEAD.equalsIgnoreCase(method))
108 {
109 httpMethod = createHeadMethod(msg);
110 }
111 else if (HttpConstants.METHOD_OPTIONS.equalsIgnoreCase(method))
112 {
113 httpMethod = createOptionsMethod(msg);
114 }
115 else if (HttpConstants.METHOD_TRACE.equalsIgnoreCase(method))
116 {
117 httpMethod = createTraceMethod(msg);
118 }
119 else
120 {
121 throw new TransformerException(HttpMessages.unsupportedMethod(method));
122 }
123
124
125 final HttpMethodParams params = (HttpMethodParams) msg.removeProperty(
126 HttpConnector.HTTP_PARAMS_PROPERTY, PropertyScope.OUTBOUND);
127 if (params != null)
128 {
129 httpMethod.setParams(params);
130 }
131 else
132 {
133
134 final String httpVersion = msg.getOutboundProperty(HttpConnector.HTTP_VERSION_PROPERTY,
135 HttpConstants.HTTP11);
136 if (HttpConstants.HTTP10.equals(httpVersion))
137 {
138 httpMethod.getParams().setVersion(HttpVersion.HTTP_1_0);
139 }
140 else
141 {
142 httpMethod.getParams().setVersion(HttpVersion.HTTP_1_1);
143 }
144 }
145
146 setHeaders(httpMethod, msg);
147
148 return httpMethod;
149 }
150 catch (final Exception e)
151 {
152 throw new TransformerException(this, e);
153 }
154 }
155
156 protected String detectHttpMethod(MuleMessage msg)
157 {
158 String method = msg.getOutboundProperty(HttpConnector.HTTP_METHOD_PROPERTY, null);
159 if (method == null)
160 {
161 method = msg.getInvocationProperty(HttpConnector.HTTP_METHOD_PROPERTY, HttpConstants.METHOD_POST);
162 }
163 return method;
164 }
165
166 protected HttpMethod createGetMethod(MuleMessage msg, String outputEncoding) throws Exception
167 {
168 final Object src = msg.getPayload();
169
170
171
172 final URI uri = getURI(msg);
173 HttpMethod httpMethod;
174 String query = uri.getRawQuery();
175
176 httpMethod = new GetMethod(uri.toString());
177 String paramName = msg.getOutboundProperty(HttpConnector.HTTP_GET_BODY_PARAM_PROPERTY, null);
178 if (paramName != null)
179 {
180 paramName = URLEncoder.encode(paramName, outputEncoding);
181
182 String paramValue;
183 Boolean encode = msg.getInvocationProperty(HttpConnector.HTTP_ENCODE_PARAMVALUE);
184 if (encode == null)
185 {
186 encode = msg.getOutboundProperty(HttpConnector.HTTP_ENCODE_PARAMVALUE, true);
187 }
188
189 if (encode)
190 {
191 paramValue = URLEncoder.encode(src.toString(), outputEncoding);
192 }
193 else
194 {
195 paramValue = src.toString();
196 }
197
198 if (!(src instanceof NullPayload) && !StringUtils.EMPTY.equals(src))
199 {
200 if (query == null)
201 {
202 query = paramName + "=" + paramValue;
203 }
204 else
205 {
206 query += "&" + paramName + "=" + paramValue;
207 }
208 }
209 }
210
211 httpMethod.setQueryString(query);
212 return httpMethod;
213 }
214
215 protected HttpMethod createPostMethod(MuleMessage msg, String outputEncoding) throws Exception
216 {
217 URI uri = getURI(msg);
218 PostMethod postMethod = new PostMethod(uri.toString());
219
220 String bodyParameterName = getBodyParameterName(msg);
221 Object src = msg.getPayload();
222 if (src instanceof Map)
223 {
224 for (Map.Entry<?, ?> entry : ((Map<?, ?>) src).entrySet())
225 {
226 postMethod.addParameter(entry.getKey().toString(), entry.getValue().toString());
227 }
228 }
229 else if (bodyParameterName != null)
230 {
231 postMethod.addParameter(bodyParameterName, src.toString());
232
233 }
234 else
235 {
236 setupEntityMethod(src, outputEncoding, msg, postMethod);
237 }
238 checkForContentType(msg, postMethod);
239
240 return postMethod;
241 }
242
243 private void checkForContentType(MuleMessage msg, EntityEnclosingMethod method)
244 {
245
246 String outgoingContentType = msg.getInvocationProperty(HttpConstants.HEADER_CONTENT_TYPE);
247 if (outgoingContentType != null)
248 {
249 method.setRequestHeader(HttpConstants.HEADER_CONTENT_TYPE, outgoingContentType);
250 }
251 }
252
253 protected String getBodyParameterName(MuleMessage message)
254 {
255 String bodyParameter = message.getOutboundProperty(HttpConnector.HTTP_POST_BODY_PARAM_PROPERTY);
256 if (bodyParameter == null)
257 {
258 bodyParameter = message.getInvocationProperty(HttpConnector.HTTP_POST_BODY_PARAM_PROPERTY);
259 }
260 return bodyParameter;
261 }
262
263 protected HttpMethod createPutMethod(MuleMessage msg, String outputEncoding) throws Exception
264 {
265 URI uri = getURI(msg);
266 PutMethod putMethod = new PutMethod(uri.toString());
267
268 Object payload = msg.getPayload();
269 setupEntityMethod(payload, outputEncoding, msg, putMethod);
270 checkForContentType(msg, putMethod);
271 return putMethod;
272 }
273
274 protected HttpMethod createDeleteMethod(MuleMessage message) throws Exception
275 {
276 URI uri = getURI(message);
277 return new DeleteMethod(uri.toString());
278 }
279
280 protected HttpMethod createHeadMethod(MuleMessage message) throws Exception
281 {
282 URI uri = getURI(message);
283 return new HeadMethod(uri.toString());
284 }
285
286 protected HttpMethod createOptionsMethod(MuleMessage message) throws Exception
287 {
288 URI uri = getURI(message);
289 return new OptionsMethod(uri.toString());
290 }
291
292 protected HttpMethod createTraceMethod(MuleMessage message) throws Exception
293 {
294 URI uri = getURI(message);
295 return new TraceMethod(uri.toString());
296 }
297
298 protected URI getURI(MuleMessage message) throws URISyntaxException, TransformerException
299 {
300 String endpointAddress = message.getOutboundProperty(MuleProperties.MULE_ENDPOINT_PROPERTY, null);
301 if (endpointAddress == null)
302 {
303 throw new TransformerException(
304 HttpMessages.eventPropertyNotSetCannotProcessRequest(MuleProperties.MULE_ENDPOINT_PROPERTY),
305 this);
306 }
307 return new URI(endpointAddress);
308 }
309
310 protected void setupEntityMethod(Object src, String encoding, MuleMessage msg,
311 EntityEnclosingMethod postMethod) throws UnsupportedEncodingException, TransformerException
312 {
313
314
315 if (!(msg.getPayload() instanceof NullPayload))
316 {
317 String outboundMimeType = (String) msg.getProperty(HttpConstants.HEADER_CONTENT_TYPE,
318 PropertyScope.OUTBOUND);
319 if (outboundMimeType == null)
320 {
321 outboundMimeType = (getEndpoint() != null ? getEndpoint().getMimeType() : null);
322 }
323 if (outboundMimeType == null)
324 {
325 outboundMimeType = HttpConstants.DEFAULT_CONTENT_TYPE;
326 logger.info("Content-Type not set on outgoing request, defaulting to: " + outboundMimeType);
327 }
328
329 if (encoding != null && !"UTF-8".equals(encoding.toUpperCase())
330 && outboundMimeType.indexOf("charset") == -1)
331 {
332 outboundMimeType += "; charset=" + encoding;
333 }
334
335
336
337 final String httpVersion = msg.getOutboundProperty(HttpConnector.HTTP_VERSION_PROPERTY,
338 HttpConstants.HTTP11);
339 if (HttpConstants.HTTP10.equals(httpVersion))
340 {
341 try
342 {
343 src = msg.getPayloadAsBytes();
344 }
345 catch (final Exception e)
346 {
347 throw new TransformerException(this, e);
348 }
349 }
350
351 if (msg.getOutboundAttachmentNames() != null && msg.getOutboundAttachmentNames().size() > 0)
352 {
353 try
354 {
355 postMethod.setRequestEntity(createMultiPart(msg, postMethod));
356 return;
357 }
358 catch (final Exception e)
359 {
360 throw new TransformerException(this, e);
361 }
362 }
363 if (src instanceof String)
364 {
365 postMethod.setRequestEntity(new StringRequestEntity(src.toString(), outboundMimeType, encoding));
366 return;
367 }
368
369 if (src instanceof InputStream)
370 {
371 postMethod.setRequestEntity(new InputStreamRequestEntity((InputStream) src, outboundMimeType));
372 }
373 else if (src instanceof byte[])
374 {
375 postMethod.setRequestEntity(new ByteArrayRequestEntity((byte[]) src, outboundMimeType));
376 }
377 else if (src instanceof OutputHandler)
378 {
379 final MuleEvent event = RequestContext.getEvent();
380 postMethod.setRequestEntity(new StreamPayloadRequestEntity((OutputHandler) src, event));
381 }
382 else
383 {
384 final byte[] buffer = SerializationUtils.serialize((Serializable) src);
385 postMethod.setRequestEntity(new ByteArrayRequestEntity(buffer, outboundMimeType));
386 }
387 }
388 else if (msg.getOutboundAttachmentNames() != null && msg.getOutboundAttachmentNames().size() > 0)
389 {
390 try
391 {
392 postMethod.setRequestEntity(createMultiPart(msg, postMethod));
393 }
394 catch (Exception e)
395 {
396 throw new TransformerException(this, e);
397 }
398 }
399 }
400
401 protected void setHeaders(HttpMethod httpMethod, MuleMessage msg) throws TransformerException
402 {
403 for (String headerName : msg.getOutboundPropertyNames())
404 {
405 String headerValue = ObjectUtils.getString(msg.getOutboundProperty(headerName), null);
406
407 if (headerName.startsWith(MuleProperties.PROPERTY_PREFIX))
408 {
409
410 headerName = new StringBuffer(30).append("X-").append(headerName).toString();
411 httpMethod.addRequestHeader(headerName, headerValue);
412
413 }
414 else if (!HttpConstants.RESPONSE_HEADER_NAMES.containsKey(headerName)
415 && !HttpConnector.HTTP_INBOUND_PROPERTIES.contains(headerName)
416 && !HttpConnector.HTTP_COOKIES_PROPERTY.equals(headerName))
417 {
418
419 httpMethod.addRequestHeader(headerName, headerValue);
420 }
421 }
422 }
423
424 protected MultipartRequestEntity createMultiPart(MuleMessage msg, EntityEnclosingMethod method)
425 throws Exception
426 {
427 Part[] parts;
428 int i = 0;
429 if (msg.getPayload() instanceof NullPayload)
430 {
431 parts = new Part[msg.getOutboundAttachmentNames().size()];
432 }
433 else
434 {
435 parts = new Part[msg.getOutboundAttachmentNames().size() + 1];
436 parts[i++] = new FilePart("payload", new ByteArrayPartSource("payload", msg.getPayloadAsBytes()));
437 }
438
439 for (final Iterator<String> iterator = msg.getOutboundAttachmentNames().iterator(); iterator.hasNext(); i++)
440 {
441 final String name = iterator.next();
442 String fileName = name;
443 final DataHandler dh = msg.getOutboundAttachment(name);
444 if (dh.getDataSource() instanceof StringDataSource)
445 {
446 final StringDataSource ds = (StringDataSource) dh.getDataSource();
447 parts[i] = new StringPart(ds.getName(), IOUtils.toString(ds.getInputStream()));
448 }
449 else
450 {
451 if (dh.getDataSource() instanceof FileDataSource)
452 {
453 fileName = ((FileDataSource) dh.getDataSource()).getFile().getName();
454 }
455 else if (dh.getDataSource() instanceof URLDataSource)
456 {
457 fileName = ((URLDataSource) dh.getDataSource()).getURL().getFile();
458
459 final int x = fileName.lastIndexOf("/");
460 if (x > -1)
461 {
462 fileName = fileName.substring(x + 1);
463 }
464 }
465 parts[i] = new FilePart(dh.getName(), new ByteArrayPartSource(fileName,
466 IOUtils.toByteArray(dh.getInputStream())), dh.getContentType(), null);
467 }
468 }
469
470 return new MultipartRequestEntity(parts, method.getParams());
471 }
472 }