View Javadoc

1   /*
2    * $Id: MuleMessageToHttpResponse.java 11517 2008-03-31 21:34:19Z dirk.olmes $
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.api.MuleMessage;
14  import org.mule.api.config.MuleProperties;
15  import org.mule.api.lifecycle.InitialisationException;
16  import org.mule.api.transformer.TransformerException;
17  import org.mule.config.MuleManifest;
18  import org.mule.transformer.AbstractMessageAwareTransformer;
19  import org.mule.transport.NullPayload;
20  import org.mule.transport.http.HttpConnector;
21  import org.mule.transport.http.HttpConstants;
22  import org.mule.transport.http.HttpResponse;
23  import org.mule.util.StringUtils;
24  
25  import java.io.IOException;
26  import java.text.SimpleDateFormat;
27  import java.util.Collection;
28  import java.util.Date;
29  import java.util.Iterator;
30  import java.util.Locale;
31  import java.util.Map;
32  
33  import org.apache.commons.httpclient.Header;
34  import org.apache.commons.httpclient.HttpVersion;
35  
36  /**
37   * <code>UMOMessageToHttpResponse</code> converts a UMOMEssage into an Http
38   * response.
39   */
40  
41  public class MuleMessageToHttpResponse extends AbstractMessageAwareTransformer
42  {
43      public static final String CUSTOM_HEADER_PREFIX = "";
44  
45      // @GuardedBy("itself")
46      private SimpleDateFormat format;
47      private String server;
48  
49      public MuleMessageToHttpResponse()
50      {
51          registerSourceType(Object.class);
52          setReturnClass(HttpResponse.class);
53      }
54  
55  
56      //@Override
57      public void initialise() throws InitialisationException
58      {
59          format = new SimpleDateFormat(HttpConstants.DATE_FORMAT, Locale.US);
60  
61          // When running with the source code, Meta information is not set
62          // so product name and version are not available, hence we hard code
63          if (MuleManifest.getProductName() == null)
64          {
65              server = "Mule/SNAPSHOT";
66          }
67          else
68          {
69              server = MuleManifest.getProductName() + "/"
70                       + MuleManifest.getProductVersion();
71          }
72      }
73  
74      public Object transform(MuleMessage msg, String outputEncoding) throws TransformerException
75      {
76          Object src = msg.getPayload();
77          // Send back the exception payload if one has been set
78          if (msg.getExceptionPayload() != null)
79          {
80              // src = context.getMessage().getExceptionPayload();
81          }
82  
83          // Note this transformer excepts Null as we must always return a result
84          // from the Http
85          // connector if a response transformer is present
86          if (src instanceof NullPayload)
87          {
88              src = StringUtils.EMPTY;
89          }
90  
91          try
92          {
93              HttpResponse response;
94              if (src instanceof HttpResponse)
95              {
96                  response = (HttpResponse)src;
97              }
98              else
99              {
100                 response = createResponse(src, outputEncoding, msg);
101             }
102 
103             // Ensure there's a content type header
104             if (!response.containsHeader(HttpConstants.HEADER_CONTENT_TYPE))
105             {
106                 response.addHeader(new Header(HttpConstants.HEADER_CONTENT_TYPE,
107                     HttpConstants.DEFAULT_CONTENT_TYPE));
108             }
109 
110             // Ensure there's a content length or transfer encoding header
111             if (!response.containsHeader(HttpConstants.HEADER_CONTENT_LENGTH)
112                 && !response.containsHeader(HttpConstants.HEADER_TRANSFER_ENCODING))
113             {
114                 if (response.hasBody())
115                 {
116                     long len = response.getContentLength();
117                     if (len < 0)
118                     {
119                         if (response.getHttpVersion().lessEquals(HttpVersion.HTTP_1_0))
120                         {
121                             throw new IOException("Chunked encoding not supported for HTTP version "
122                                                   + response.getHttpVersion());
123                         }
124                         Header header = new Header(HttpConstants.HEADER_TRANSFER_ENCODING, "chunked");
125                         response.addHeader(header);
126                     }
127                     else
128                     {
129                         Header header = new Header(HttpConstants.HEADER_CONTENT_LENGTH, Long.toString(len));
130                         response.setHeader(header);
131                     }
132                 }
133                 else
134                 {
135                     Header header = new Header(HttpConstants.HEADER_CONTENT_LENGTH, "0");
136                     response.addHeader(header);
137                 }
138             }
139 
140             if (!response.containsHeader(HttpConstants.HEADER_CONNECTION))
141             {
142                 // See if the the client explicitly handles connection persistence
143                 String connHeader = msg.getStringProperty(HttpConstants.HEADER_CONNECTION, null);
144                 if (connHeader != null)
145                 {
146                     if (connHeader.equalsIgnoreCase("keep-alive"))
147                     {
148                         Header header = new Header(HttpConstants.HEADER_CONNECTION, "keep-alive");
149                         response.addHeader(header);
150                         response.setKeepAlive(true);
151                     }
152                     if (connHeader.equalsIgnoreCase("close"))
153                     {
154                         Header header = new Header(HttpConstants.HEADER_CONNECTION, "close");
155                         response.addHeader(header);
156                         response.setKeepAlive(false);
157                     }
158                 }
159                 else
160                 {
161                     // Use protocol default connection policy
162                     if (response.getHttpVersion().greaterEquals(HttpVersion.HTTP_1_1))
163                     {
164                         response.setKeepAlive(true);
165                     }
166                     else
167                     {
168                         response.setKeepAlive(false);
169                     }
170                 }
171             }
172             if ("HEAD".equalsIgnoreCase(msg.getStringProperty(HttpConnector.HTTP_METHOD_PROPERTY, null)))
173             {
174                 // this is a head request, we don't want to send the actual content
175                 response.setBody((MuleMessage) null);
176             }
177             return response;
178         }
179         catch (IOException e)
180         {
181             throw new TransformerException(this, e);
182         }
183 
184     }
185 
186     protected HttpResponse createResponse(Object src, String encoding, MuleMessage msg)
187         throws IOException, TransformerException
188     {
189         HttpResponse response = new HttpResponse();
190 
191         int status = msg.getIntProperty(HttpConnector.HTTP_STATUS_PROPERTY, HttpConstants.SC_OK);
192         String version = msg.getStringProperty(HttpConnector.HTTP_VERSION_PROPERTY, HttpConstants.HTTP11);
193         String etag = msg.getStringProperty(HttpConstants.HEADER_ETAG, null);
194         
195         String date;
196         synchronized (format)
197         {
198             date = format.format(new Date());
199         }
200 
201         String contentType = msg.getStringProperty(HttpConstants.HEADER_CONTENT_TYPE,
202             HttpConstants.DEFAULT_CONTENT_TYPE);
203 
204         response.setStatusLine(HttpVersion.parse(version), status);
205         response.setHeader(new Header(HttpConstants.HEADER_CONTENT_TYPE, contentType));
206         response.setHeader(new Header(HttpConstants.HEADER_DATE, date));
207         response.setHeader(new Header(HttpConstants.HEADER_SERVER, server));
208         if (msg.getProperty(HttpConstants.HEADER_EXPIRES) == null)
209         {
210             response.setHeader(new Header(HttpConstants.HEADER_EXPIRES, date));
211         }
212         if (etag != null)
213         {
214             response.setHeader(new Header(HttpConstants.HEADER_ETAG, etag));
215         }
216         response.setFallbackCharset(encoding);
217 
218         Collection headerNames = HttpConstants.RESPONSE_HEADER_NAMES.values();
219         String headerName, value;
220         for (Iterator iterator = headerNames.iterator(); iterator.hasNext();)
221         {
222             headerName = (String)iterator.next();
223             value = msg.getStringProperty(headerName, null);
224             if (value != null)
225             {
226                 response.setHeader(new Header(headerName, value));
227             }
228         }
229 
230         // Custom responseHeaderNames
231         Map customHeaders = (Map)msg.getProperty(HttpConnector.HTTP_CUSTOM_HEADERS_MAP_PROPERTY);
232         if (customHeaders != null)
233         {
234             Map.Entry entry;
235             for (Iterator iterator = customHeaders.entrySet().iterator(); iterator.hasNext();)
236             {
237                 entry = (Map.Entry)iterator.next();
238                 if (entry.getValue() != null)
239                 {
240                     response.setHeader(new Header(entry.getKey().toString(), entry.getValue().toString()));
241                 }
242             }
243         }
244 
245         // Mule properties
246         String user = msg.getStringProperty(MuleProperties.MULE_USER_PROPERTY, null);
247         if (user != null)
248         {
249             response.setHeader(new Header(CUSTOM_HEADER_PREFIX + MuleProperties.MULE_USER_PROPERTY, user));
250         }
251         if (msg.getCorrelationId() != null)
252         {
253             response.setHeader(new Header(CUSTOM_HEADER_PREFIX + MuleProperties.MULE_CORRELATION_ID_PROPERTY,
254                 msg.getCorrelationId()));
255             response.setHeader(new Header(CUSTOM_HEADER_PREFIX
256                                           + MuleProperties.MULE_CORRELATION_GROUP_SIZE_PROPERTY,
257                 String.valueOf(msg.getCorrelationGroupSize())));
258             response.setHeader(new Header(CUSTOM_HEADER_PREFIX
259                                           + MuleProperties.MULE_CORRELATION_SEQUENCE_PROPERTY,
260                 String.valueOf(msg.getCorrelationSequence())));
261         }
262         if (msg.getReplyTo() != null)
263         {
264             response.setHeader(new Header(CUSTOM_HEADER_PREFIX + MuleProperties.MULE_REPLY_TO_PROPERTY,
265                 msg.getReplyTo().toString()));
266         }
267         
268         response.setBody(msg);
269         
270         return response;
271     }
272 
273     public boolean isAcceptNull()
274     {
275         return true;
276     }
277 }