View Javadoc

1   /*
2    * $Id: ObjectToHttpClientMethodRequest.java 12100 2008-06-19 08:58:48Z rossmason $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
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.transformer.AbstractMessageAwareTransformer;
20  import org.mule.transport.NullPayload;
21  import org.mule.transport.http.HttpConnector;
22  import org.mule.transport.http.HttpConstants;
23  import org.mule.transport.http.StreamPayloadRequestEntity;
24  import org.mule.transport.http.i18n.HttpMessages;
25  import org.mule.util.StringUtils;
26  import org.mule.util.expression.ExpressionEvaluatorManager;
27  
28  import java.io.InputStream;
29  import java.io.Serializable;
30  import java.io.UnsupportedEncodingException;
31  import java.net.URI;
32  import java.net.URLEncoder;
33  import java.util.Iterator;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.Set;
37  
38  import org.apache.commons.httpclient.HttpMethod;
39  import org.apache.commons.httpclient.HttpVersion;
40  import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
41  import org.apache.commons.httpclient.methods.DeleteMethod;
42  import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
43  import org.apache.commons.httpclient.methods.GetMethod;
44  import org.apache.commons.httpclient.methods.HeadMethod;
45  import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
46  import org.apache.commons.httpclient.methods.OptionsMethod;
47  import org.apache.commons.httpclient.methods.PostMethod;
48  import org.apache.commons.httpclient.methods.PutMethod;
49  import org.apache.commons.httpclient.methods.StringRequestEntity;
50  import org.apache.commons.httpclient.methods.TraceMethod;
51  import org.apache.commons.httpclient.params.HttpMethodParams;
52  import org.apache.commons.lang.SerializationUtils;
53  
54  /**
55   * <code>ObjectToHttpClientMethodRequest</code> transforms a MuleMessage into a
56   * HttpClient HttpMethod that represents an HttpRequest.
57   */
58  
59  public class ObjectToHttpClientMethodRequest extends AbstractMessageAwareTransformer
60  {
61  
62      public ObjectToHttpClientMethodRequest()
63      {
64          setReturnClass(HttpMethod.class);
65          registerSourceType(MuleMessage.class);
66          registerSourceType(byte[].class);
67          registerSourceType(String.class);
68          registerSourceType(InputStream.class);
69          registerSourceType(OutputHandler.class);
70          registerSourceType(NullPayload.class);
71      }
72  
73      protected int addParameters(String queryString, PostMethod postMethod, MuleMessage msg)
74      {
75          // Parse the HTTP argument list and convert to a NameValuePair
76          // collection
77  
78          if (StringUtils.isBlank(queryString))
79          {
80              return 0;
81          }
82  
83          String currentParam;
84          int equals;
85          equals = queryString.indexOf("&");
86          if (equals > -1)
87          {
88              currentParam = queryString.substring(0, equals);
89              queryString = queryString.substring(equals + 1);
90          }
91          else
92          {
93              currentParam = queryString;
94              queryString = StringUtils.EMPTY;
95          }
96          int parameterIndex = -1;
97          while (StringUtils.isNotBlank(currentParam))
98          {
99              String paramName, paramValue;
100             equals = currentParam.indexOf("=");
101             if (equals > -1)
102             {
103                 paramName = currentParam.substring(0, equals);
104                 paramValue = currentParam.substring(equals + 1);
105                 //Run query params through the expression evaluator
106 //                Object temp = ExpressionEvaluatorManager.evaluate(paramValue, msg, "$[", true);
107 //                if (temp != null)
108 //                {
109 //                    //Process param collections
110 //                    if (temp instanceof List)
111 //                    {
112 //                        StringBuffer buf = new StringBuffer();
113 //                        List list = (List) temp;
114 //                        for (Iterator iterator = list.iterator(); iterator.hasNext();)
115 //                        {
116 //                            Object object = iterator.next();
117 //                            buf.append(object).append(",");
118 //                        }
119 //                        parameterIndex++;
120 //                        postMethod.addParameter(paramName, buf.toString());
121 //                    }
122 //                    else if (temp instanceof Map)
123 //                    {
124 //                        Map map = (Map) temp;
125 //                        for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();)
126 //                        {
127 //                            Map.Entry entry = (Map.Entry) iterator.next();
128 //                            parameterIndex++;
129 //                            postMethod.addParameter(entry.getKey().toString(), entry.getValue().toString());
130 //                        }
131 //                    }
132 //                    else
133 //                    {
134 //                        parameterIndex++;
135 //                        postMethod.addParameter(paramName, temp.toString());
136 //                    }
137 //                }
138 //                else
139 //                {
140                     parameterIndex++;
141                     postMethod.addParameter(paramName, paramValue);
142                 //}
143 
144 
145             }
146             equals = queryString.indexOf("&");
147             if (equals > -1)
148             {
149                 currentParam = queryString.substring(0, equals);
150                 queryString = queryString.substring(equals + 1);
151             }
152             else
153             {
154                 currentParam = queryString;
155                 queryString = StringUtils.EMPTY;
156             }
157         }
158         return parameterIndex + 1;
159     }
160 
161     public Object transform(MuleMessage msg, String outputEncoding) throws TransformerException
162     {
163         Object src = msg.getPayload();
164 
165         String endpoint = msg.getStringProperty(MuleProperties.MULE_ENDPOINT_PROPERTY, null);
166         if (endpoint == null)
167         {
168             throw new TransformerException(
169                     HttpMessages.eventPropertyNotSetCannotProcessRequest(
170                             MuleProperties.MULE_ENDPOINT_PROPERTY), this);
171         }
172 
173         String method = msg.getStringProperty(HttpConnector.HTTP_METHOD_PROPERTY, "POST");
174         try
175         {
176             //Allow Expressions to be embedded
177             endpoint = endpoint.replaceAll("\\[", "\\{");
178             endpoint = endpoint.replaceAll("\\]", "\\}");
179             endpoint = ExpressionEvaluatorManager.parse(endpoint, msg, true);
180             URI uri = new URI(endpoint);
181             HttpMethod httpMethod;
182 
183             if (HttpConstants.METHOD_GET.equals(method))
184             {
185                 httpMethod = new GetMethod(uri.toString());
186                 String paramName = URLEncoder.encode(msg.getStringProperty(HttpConnector.HTTP_GET_BODY_PARAM_PROPERTY,
187                         HttpConnector.DEFAULT_HTTP_GET_BODY_PARAM_PROPERTY), outputEncoding);
188                 String paramValue = URLEncoder.encode(src.toString(), outputEncoding);
189 
190                 String query = uri.getRawQuery();
191                 if (!(src instanceof NullPayload) && !StringUtils.EMPTY.equals(src))
192                 {
193                     if (query == null)
194                     {
195                         query = paramName + "=" + paramValue;
196                     }
197                     else
198                     {
199                         query += "&" + paramName + "=" + paramValue;
200                     }
201                 }
202                 httpMethod.setQueryString(query);
203 
204             }
205             else if (HttpConstants.METHOD_POST.equalsIgnoreCase(method))
206             {
207                 PostMethod postMethod = new PostMethod(uri.toString());
208                 String paramName = msg.getStringProperty(HttpConnector.HTTP_POST_BODY_PARAM_PROPERTY, null);
209 
210                 if (paramName == null)
211                 {
212                     // Call method to manage the parameter array
213                     addParameters(uri.getQuery(), postMethod, msg);
214                     setupEntityMethod(src, outputEncoding, msg, uri, postMethod);
215                 }
216                 else
217                 {
218                     postMethod.addParameter(paramName, src.toString());
219                 }
220 
221                 httpMethod = postMethod;
222             }
223             else if (HttpConstants.METHOD_PUT.equalsIgnoreCase(method))
224             {
225                 PutMethod putMethod = new PutMethod(uri.toString());
226 
227                 setupEntityMethod(src, outputEncoding, msg, uri, putMethod);
228 
229                 httpMethod = putMethod;
230             }
231             else if (HttpConstants.METHOD_DELETE.equalsIgnoreCase(method))
232             {
233                 httpMethod = new DeleteMethod(uri.toString());
234             }
235             else if (HttpConstants.METHOD_HEAD.equalsIgnoreCase(method))
236             {
237                 httpMethod = new HeadMethod(uri.toString());
238             }
239             else if (HttpConstants.METHOD_OPTIONS.equalsIgnoreCase(method))
240             {
241                 httpMethod = new OptionsMethod(uri.toString());
242             }
243             else if (HttpConstants.METHOD_TRACE.equalsIgnoreCase(method))
244             {
245                 httpMethod = new TraceMethod(uri.toString());
246             }
247             else
248             {
249                 throw new TransformerException(HttpMessages.unsupportedMethod(method));
250             }
251 
252             // Allow the user to set HttpMethodParams as an object on the message
253             HttpMethodParams params = (HttpMethodParams) msg.removeProperty(HttpConnector.HTTP_PARAMS_PROPERTY);
254             if (params != null)
255             {
256                 httpMethod.setParams(params);
257             }
258             else
259             {
260                 // TODO we should probably set other properties here
261                 String httpVersion = msg.getStringProperty(HttpConnector.HTTP_VERSION_PROPERTY,
262                         HttpConstants.HTTP11);
263                 if (HttpConstants.HTTP10.equals(httpVersion))
264                 {
265                     httpMethod.getParams().setVersion(HttpVersion.HTTP_1_0);
266                 }
267                 else
268                 {
269                     httpMethod.getParams().setVersion(HttpVersion.HTTP_1_1);
270                 }
271             }
272 
273             setHeaders(httpMethod, msg);
274 
275             return httpMethod;
276         }
277         catch (Exception e)
278         {
279             throw new TransformerException(this, e);
280         }
281     }
282 
283     protected void setupEntityMethod(Object src,
284                                      String encoding,
285                                      MuleMessage msg,
286                                      URI uri,
287                                      EntityEnclosingMethod postMethod)
288             throws UnsupportedEncodingException, TransformerException
289     {
290         // Dont set a POST payload if the body is a Null Payload.
291         // This way client calls
292         // can control if a POST body is posted explicitly
293         if (!(msg.getPayload() instanceof NullPayload))
294         {
295             // See if we have a MIME type set
296             String mimeType = msg.getStringProperty(HttpConstants.HEADER_CONTENT_TYPE, null);
297 
298             if (src instanceof String)
299             {
300                 // Ensure that we strip the encoding information from the
301                 // encoding type
302                 if (mimeType != null)
303                 {
304                     int parameterIndex = mimeType.indexOf(";");
305                     if (parameterIndex > 0)
306                     {
307                         mimeType = mimeType.substring(0, parameterIndex);
308                     }
309                 }
310                 if (mimeType == null)
311                 {
312                     mimeType = HttpConstants.DEFAULT_CONTENT_TYPE;
313                 }
314 
315                 postMethod.setRequestEntity(new StringRequestEntity(src.toString(), mimeType,
316                         encoding));
317                 return;
318             }
319 
320 
321             if (mimeType == null)
322             {
323                 mimeType = HttpConstants.DEFAULT_CONTENT_TYPE;
324             }
325 
326             if (encoding != null
327                     && !"UTF-8".equals(encoding.toUpperCase())
328                     && mimeType.indexOf("charset") == -1)
329             {
330                 mimeType += "; charset=" + encoding;
331             }
332 
333             if (src instanceof InputStream)
334             {
335                 // TODO Danger here! We don't know if the content is
336                 // really text or not
337                 if (mimeType == null)
338                 {
339                     mimeType = HttpConstants.DEFAULT_CONTENT_TYPE;
340                 }
341                 postMethod.setRequestEntity(new InputStreamRequestEntity((InputStream) src,
342                         mimeType));
343             }
344             else if (src instanceof byte[])
345             {
346                 if (mimeType == null)
347                 {
348                     mimeType = HttpConstants.DEFAULT_CONTENT_TYPE;
349                 }
350                 postMethod.setRequestEntity(new ByteArrayRequestEntity((byte[]) src,
351                         mimeType));
352             }
353             else if (src instanceof OutputHandler)
354             {
355                 MuleEvent event = RequestContext.getEvent();
356                 postMethod.setRequestEntity(new StreamPayloadRequestEntity((OutputHandler) src, event));
357             }
358             else
359             {
360                 if (mimeType == null)
361                 {
362                     mimeType = HttpConstants.DEFAULT_CONTENT_TYPE;
363                 }
364 
365                 byte[] buffer = SerializationUtils.serialize((Serializable) src);
366                 postMethod.setRequestEntity(new ByteArrayRequestEntity(buffer, mimeType));
367             }
368         }
369 
370     }
371 
372     protected void setHeaders(HttpMethod httpMethod, MuleMessage msg)
373     {
374         // Standard requestHeaders
375         String headerValue;
376         String headerName;
377         for (Iterator iterator = msg.getPropertyNames().iterator(); iterator.hasNext();)
378         {
379             headerName = (String) iterator.next();
380 
381             headerValue = msg.getStringProperty(headerName, null);
382             if (HttpConstants.REQUEST_HEADER_NAMES.get(headerName) == null)
383             {
384                 if (headerName.startsWith(MuleProperties.PROPERTY_PREFIX))
385                 {
386                     headerName = new StringBuffer(30).append("X-").append(headerName).toString();
387                 }
388 
389                 httpMethod.addRequestHeader(headerName, headerValue);
390             }
391         }
392 
393         Map customHeaders = (Map) msg.getProperty(HttpConnector.HTTP_CUSTOM_HEADERS_MAP_PROPERTY);
394         if (customHeaders != null)
395         {
396             Map.Entry entry;
397             for (Iterator iterator = customHeaders.entrySet().iterator(); iterator.hasNext();)
398             {
399                 entry = (Map.Entry) iterator.next();
400                 if (entry.getValue() != null)
401                 {
402                     httpMethod.addRequestHeader(entry.getKey().toString(), entry.getValue().toString());
403                 }
404             }
405         }
406 
407         Set attNams = msg.getAttachmentNames();
408         if (msg.getPayload() instanceof InputStream
409                 && attNams != null && attNams.size() > 0)
410         {
411             // must set this for receiver to properly parse attachments
412             httpMethod.addRequestHeader(HttpConstants.HEADER_CONTENT_TYPE, "multipart/related");
413         }
414     }
415 
416     protected String paramToString(Object param)
417     {
418         StringBuffer buf = new StringBuffer();
419         if (param instanceof List)
420         {
421             List list = (List) param;
422             for (Iterator iterator = list.iterator(); iterator.hasNext();)
423             {
424                 Object object = iterator.next();
425                 buf.append(object).append(",");
426             }
427             return buf.toString();
428         }
429         else if (param instanceof Map)
430         {
431             Map map = (Map) param;
432             for (Iterator iterator = map.entrySet().iterator(); iterator.hasNext();)
433             {
434                 Map.Entry entry = (Map.Entry) iterator.next();
435                 buf.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
436             }
437             return buf.toString().substring(0, buf.length() - 1);
438         }
439         else
440         {
441             return param.toString();
442         }
443     }
444 }