KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mule > providers > http > HttpMessageReceiver


1 /*
2  * $Id: HttpMessageReceiver.java 3798 2006-11-04 04:07:14Z aperepel $
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 MuleSource MPL
7  * license, a copy of which has been included with this distribution in the
8  * LICENSE.txt file.
9  */

10
11 package org.mule.providers.http;
12
13 import java.io.IOException JavaDoc;
14 import java.net.Socket JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.Map JavaDoc;
18
19 import javax.resource.spi.work.Work JavaDoc;
20
21 import org.apache.commons.httpclient.Cookie;
22 import org.apache.commons.httpclient.Header;
23 import org.apache.commons.lang.ObjectUtils;
24 import org.mule.config.i18n.Message;
25 import org.mule.config.i18n.Messages;
26 import org.mule.impl.MuleEvent;
27 import org.mule.impl.MuleMessage;
28 import org.mule.impl.MuleSession;
29 import org.mule.impl.RequestContext;
30 import org.mule.providers.AbstractMessageReceiver;
31 import org.mule.providers.ConnectException;
32 import org.mule.providers.NullPayload;
33 import org.mule.providers.tcp.TcpMessageReceiver;
34 import org.mule.umo.UMOComponent;
35 import org.mule.umo.UMOMessage;
36 import org.mule.umo.endpoint.UMOEndpoint;
37 import org.mule.umo.endpoint.UMOEndpointURI;
38 import org.mule.umo.lifecycle.InitialisationException;
39 import org.mule.umo.provider.UMOConnector;
40 import org.mule.umo.provider.UMOMessageAdapter;
41 import org.mule.util.MapUtils;
42
43 /**
44  * <code>HttpMessageReceiver</code> is a simple http server that can be used to
45  * listen for HTTP requests on a particular port.
46  */

47 public class HttpMessageReceiver extends TcpMessageReceiver
48 {
49
50     public HttpMessageReceiver(UMOConnector connector, UMOComponent component, UMOEndpoint endpoint)
51         throws InitialisationException
52     {
53         super(connector, component, endpoint);
54     }
55
56     protected Work JavaDoc createWork(Socket JavaDoc socket) throws IOException JavaDoc
57     {
58         return new HttpWorker(socket);
59     }
60
61     public void doConnect() throws ConnectException
62     {
63         // If we already have an endpoint listening on this socket don't try and
64
// start another serversocket
65
if (shouldConnect())
66         {
67             super.doConnect();
68         }
69     }
70
71     protected boolean shouldConnect()
72     {
73         StringBuffer JavaDoc requestUri = new StringBuffer JavaDoc(80);
74         requestUri.append(endpoint.getProtocol()).append("://");
75         requestUri.append(endpoint.getEndpointURI().getHost());
76         requestUri.append(":").append(endpoint.getEndpointURI().getPort());
77         requestUri.append("*");
78         AbstractMessageReceiver[] temp = connector.getReceivers(requestUri.toString());
79         for (int i = 0; i < temp.length; i++)
80         {
81             AbstractMessageReceiver abstractMessageReceiver = temp[i];
82             if (abstractMessageReceiver.isConnected())
83             {
84                 return false;
85             }
86         }
87         return true;
88     }
89
90     private class HttpWorker implements Work JavaDoc
91     {
92
93         private HttpServerConnection conn = null;
94         private String JavaDoc cookieSpec;
95         private boolean enableCookies = false;
96
97         public HttpWorker(Socket JavaDoc socket) throws IOException JavaDoc
98         {
99             if (endpoint.getEncoding() != null)
100             {
101                 conn = new HttpServerConnection(socket, endpoint.getEncoding());
102             }
103             else
104             {
105                 conn = new HttpServerConnection(socket);
106             }
107
108             cookieSpec = MapUtils.getString(endpoint.getProperties(),
109                 HttpConnector.HTTP_COOKIE_SPEC_PROPERTY, ((HttpConnector)connector).getCookieSpec());
110
111             enableCookies = MapUtils.getBooleanValue(endpoint.getProperties(),
112                 HttpConnector.HTTP_ENABLE_COOKIES_PROPERTY, ((HttpConnector)connector).isEnableCookies());
113         }
114
115         public void run()
116         {
117             try
118             {
119                 do
120                 {
121                     conn.setKeepAlive(false);
122                     HttpRequest request = conn.readRequest();
123                     if (request == null)
124                     {
125                         break;
126                     }
127
128                     Map JavaDoc headers = new HashMap JavaDoc();
129                     for (Iterator JavaDoc rhi = request.getHeaderIterator(); rhi.hasNext();)
130                     {
131                         Header header = (Header)rhi.next();
132                         String JavaDoc headerName = header.getName();
133                         Object JavaDoc headerValue = header.getValue();
134
135                         // fix Mule headers?
136
if (headerName.startsWith("X-MULE"))
137                         {
138                             headerName = headerName.substring(2);
139                         }
140                         // Parse cookies?
141
else if (headerName.equals(HttpConnector.HTTP_COOKIES_PROPERTY))
142                         {
143                             if (enableCookies)
144                             {
145                                 Cookie[] cookies = CookieHelper.parseCookies(header, cookieSpec);
146                                 if (cookies.length > 0)
147                                 {
148                                     // yum!
149
headerValue = cookies;
150                                 }
151                                 else
152                                 {
153                                     // bad cookies?!
154
continue;
155                                 }
156                             }
157                             else
158                             {
159                                 // no cookies for you!
160
continue;
161                             }
162                         }
163
164                         // accept header & value
165
headers.put(headerName, headerValue);
166                     }
167
168                     RequestLine reqLine = request.getRequestLine();
169                     headers.put(HttpConnector.HTTP_METHOD_PROPERTY, reqLine.getMethod());
170                     headers.put(HttpConnector.HTTP_REQUEST_PROPERTY, reqLine.getUri());
171                     headers.put(HttpConnector.HTTP_VERSION_PROPERTY, reqLine.getHttpVersion().toString());
172                     headers.put(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY, cookieSpec);
173
174                     // TODO Mule 2.0 generic way to set stream message adapter
175
UMOMessageAdapter adapter;
176                     Object JavaDoc body;
177                     if (endpoint.isStreaming() && request.getBody() != null)
178                     {
179                         adapter = connector.getStreamMessageAdapter(request.getBody(), conn.getOutputStream());
180                         for (Iterator JavaDoc iterator = headers.entrySet().iterator(); iterator.hasNext();)
181                         {
182                             Map.Entry JavaDoc entry = (Map.Entry JavaDoc)iterator.next();
183                             adapter.setProperty((String JavaDoc)entry.getKey(), entry.getValue());
184                         }
185                     }
186                     else
187                     {
188                         // respond with status code 100, for Expect handshake
189
// according to rfc 2616 and http 1.1
190
// the processing will continue and the request will be fully
191
// read immediately after
192
if (headers.get(HttpConnector.HTTP_VERSION_PROPERTY).equals(HttpConstants.HTTP11))
193                         {
194                             // just in case we have something other than String in
195
// the headers map
196
String JavaDoc expectHeaderValue = ObjectUtils.toString(
197                                 headers.get(HttpConstants.HEADER_EXPECT)).toLowerCase();
198                             if (HttpConstants.HEADER_EXPECT_CONTINUE_REQUEST_VALUE.equals(expectHeaderValue))
199                             {
200                                 HttpResponse expected = new HttpResponse();
201                                 expected.setStatusLine(reqLine.getHttpVersion(), HttpConstants.SC_CONTINUE);
202                                 final MuleEvent event = new MuleEvent(new MuleMessage(expected), endpoint,
203                                     new MuleSession(component), true);
204                                 RequestContext.setEvent(event);
205                                 expected = (HttpResponse)connector.getDefaultResponseTransformer().transform(
206                                     expected);
207                                 conn.writeResponse(expected);
208                             }
209                         }
210
211                         body = request.getBodyBytes();
212                         if (body == null)
213                         {
214                             body = reqLine.getUri();
215                         }
216                         adapter = connector.getMessageAdapter(new Object JavaDoc[]{body, headers});
217                     }
218
219                     UMOMessage message = new MuleMessage(adapter);
220
221                     if (logger.isDebugEnabled())
222                     {
223                         logger.debug(message.getProperty(HttpConnector.HTTP_REQUEST_PROPERTY));
224                     }
225
226                     // determine if the request path on this request denotes a
227
// different receiver
228
AbstractMessageReceiver receiver = getTargetReceiver(message, endpoint);
229
230                     // the respone only needs to be transformed explicitly if
231
// A) the request was not served or B) a null result was returned
232
HttpResponse response;
233                     if (receiver != null)
234                     {
235                         UMOMessage returnMessage = receiver.routeMessage(message, endpoint.isSynchronous(), /*
236                                                                                                              * TODO
237                                                                                                              * streaming
238                                                                                                              */

239                         null);
240                         Object JavaDoc tempResponse;
241                         if (returnMessage != null)
242                         {
243                             tempResponse = returnMessage.getPayload();
244                         }
245                         else
246                         {
247                             tempResponse = new NullPayload();
248                         }
249                         // This removes the need for users to explicitly adding
250
// the response transformer ObjectToHttpResponse in
251
// their config
252
if (tempResponse instanceof HttpResponse)
253                         {
254                             response = (HttpResponse)tempResponse;
255                         }
256                         else
257                         {
258                             response = (HttpResponse)connector.getDefaultResponseTransformer().transform(
259                                 tempResponse);
260                         }
261                         response.disableKeepAlive(!((HttpConnector)connector).isKeepAlive());
262                     }
263                     else
264                     {
265                         UMOEndpointURI uri = endpoint.getEndpointURI();
266                         String JavaDoc failedPath = uri.getScheme() + "://" + uri.getHost() + ":" + uri.getPort()
267                                             + getRequestPath(message);
268
269                         if (logger.isDebugEnabled())
270                         {
271                             logger.debug("Failed to bind to " + failedPath);
272                         }
273
274                         response = new HttpResponse();
275                         response.setStatusLine(reqLine.getHttpVersion(), HttpConstants.SC_NOT_FOUND);
276                         response.setBodyString(new Message(Messages.CANNOT_BIND_TO_ADDRESS_X, failedPath).toString());
277                         RequestContext.setEvent(new MuleEvent(new MuleMessage(response), endpoint,
278                             new MuleSession(component), true));
279                         // The DefaultResponseTransformer will set the necessary
280
// headers
281
response = (HttpResponse)connector.getDefaultResponseTransformer()
282                             .transform(response);
283                     }
284
285                     conn.writeResponse(response);
286                 }
287                 while (conn.isKeepAlive());
288             }
289             catch (Exception JavaDoc e)
290             {
291                 handleException(e);
292             }
293             finally
294             {
295                 conn.close();
296                 conn = null;
297             }
298         }
299
300         public void release()
301         {
302             conn.close();
303             conn = null;
304         }
305     }
306
307     protected String JavaDoc getRequestPath(UMOMessage message)
308     {
309         String JavaDoc path = (String JavaDoc)message.getProperty(HttpConnector.HTTP_REQUEST_PROPERTY);
310         int i = path.indexOf("?");
311         if (i > -1)
312         {
313             path = path.substring(0, i);
314         }
315         return path;
316     }
317
318     protected AbstractMessageReceiver getTargetReceiver(UMOMessage message, UMOEndpoint endpoint)
319         throws ConnectException
320     {
321         String JavaDoc path = (String JavaDoc)message.getProperty(HttpConnector.HTTP_REQUEST_PROPERTY);
322         int i = path.indexOf("?");
323         if (i > -1)
324         {
325             path = path.substring(0, i);
326         }
327
328         StringBuffer JavaDoc requestUri = new StringBuffer JavaDoc();
329         requestUri.append(endpoint.getProtocol()).append("://");
330         requestUri.append(endpoint.getEndpointURI().getHost());
331         requestUri.append(":").append(endpoint.getEndpointURI().getPort());
332
333         // first check that there is a receiver on the root address
334
if (logger.isTraceEnabled())
335         {
336             logger.trace("Looking up receiver on connector: " + connector.getName() + " with URI key: "
337                          + requestUri.toString());
338         }
339
340         AbstractMessageReceiver receiver = connector.getReceiver(requestUri.toString());
341
342         // If no receiver on the root and there is a request path, look up the
343
// received based on the root plus request path
344
if (receiver == null && !"/".equals(path))
345         {
346             // remove anything after the last '/'
347
int x = path.lastIndexOf("/");
348             if (x > 1 && path.indexOf(".") > x)
349             {
350                 requestUri.append(path.substring(0, x));
351             }
352             else
353             {
354                 requestUri.append(path);
355             }
356
357             if (logger.isTraceEnabled())
358             {
359                 logger.trace("Secondary lookup of receiver on connector: " + connector.getName()
360                              + " with URI key: " + requestUri.toString());
361             }
362
363             // try again
364
receiver = connector.getReceiver(requestUri.toString());
365             if (receiver == null && logger.isWarnEnabled())
366             {
367                 logger.warn("No receiver found with secondary lookup on connector: " + connector.getName()
368                             + " with URI key: " + requestUri.toString());
369                 logger.warn("Receivers on connector are: "
370                             + MapUtils.toString(connector.getReceivers(), true));
371             }
372         }
373
374         return receiver;
375     }
376
377 }
378
Popular Tags