View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.servlet;
8   
9   import org.mule.api.MuleEvent;
10  import org.mule.api.MuleException;
11  import org.mule.api.MuleMessage;
12  import org.mule.api.endpoint.EndpointException;
13  import org.mule.api.endpoint.EndpointURI;
14  import org.mule.api.endpoint.InboundEndpoint;
15  import org.mule.api.lifecycle.InitialisationException;
16  import org.mule.api.transport.MessageReceiver;
17  import org.mule.api.transport.NoReceiverForEndpointException;
18  import org.mule.api.transport.PropertyScope;
19  import org.mule.endpoint.DynamicURIInboundEndpoint;
20  import org.mule.endpoint.MuleEndpointURI;
21  import org.mule.routing.filters.WildcardFilter;
22  import org.mule.transport.http.HttpConnector;
23  import org.mule.transport.http.HttpConstants;
24  import org.mule.transport.http.HttpMessageReceiver;
25  import org.mule.transport.http.i18n.HttpMessages;
26  import org.mule.transport.service.TransportFactory;
27  import org.mule.transport.servlet.i18n.ServletMessages;
28  import org.mule.util.PropertiesUtils;
29  
30  import java.io.IOException;
31  import java.util.Map;
32  import java.util.Properties;
33  
34  import javax.servlet.ServletException;
35  import javax.servlet.http.HttpServletRequest;
36  import javax.servlet.http.HttpServletResponse;
37  
38  /**
39   * Receives Http requests via a Servlet and routes them to listeners with servlet://
40   * endpoints
41   * <p/>
42   */
43  public class MuleReceiverServlet extends AbstractReceiverServlet
44  {
45      /**
46       * Serial version
47       */
48      private static final long serialVersionUID = 6631307373079767439L;
49  
50      protected ServletConnector connector = null;
51  
52      private boolean useCachedHttpServletRequest = false;
53  
54      @Override
55      protected void doInit() throws ServletException
56      {
57          connector = getOrCreateServletConnector(getServletConfig().getInitParameter(SERVLET_CONNECTOR_NAME_PROPERTY));
58      }
59  
60      protected ServletConnector getOrCreateServletConnector(String name) throws ServletException
61      {
62          ServletConnector servletConnector;
63          if (name == null)
64          {
65              servletConnector = (ServletConnector) new TransportFactory(muleContext).getConnectorByProtocol("servlet");
66              if (servletConnector == null)
67              {
68                  servletConnector = new ServletConnector(muleContext);
69                  servletConnector.setName("_generatedServletConnector");
70                  try
71                  {
72                      muleContext.getRegistry().registerConnector(servletConnector);
73                  }
74                  catch (MuleException e)
75                  {
76                      throw new ServletException("Failed to register the ServletConnector", e);
77                  }
78              }
79          }
80          else
81          {
82              servletConnector = (ServletConnector) muleContext.getRegistry().lookupConnector(name);
83              if (servletConnector == null)
84              {
85                  throw new ServletException(ServletMessages.noServletConnectorFound(name).toString());
86              }
87          }
88          this.useCachedHttpServletRequest = servletConnector.isUseCachedHttpServletRequest();
89          return servletConnector;
90      }
91  
92      protected void setupRequestMessage(HttpServletRequest request,
93                                         MuleMessage requestMessage,
94                                         MessageReceiver receiver)
95      {
96  
97          EndpointURI uri = receiver.getEndpointURI();
98          String reqUri = request.getRequestURI();
99          requestMessage.setProperty(HttpConnector.HTTP_REQUEST_PATH_PROPERTY, reqUri, PropertyScope.INBOUND);
100 
101         String queryString = request.getQueryString();
102         if (queryString != null)
103         {
104             reqUri += "?" + queryString;
105         }
106 
107         requestMessage.setProperty(HttpConnector.HTTP_REQUEST_PROPERTY, reqUri, PropertyScope.INBOUND);
108 
109         String path;
110         if ("servlet".equals(uri.getScheme()))
111         {
112             path = HttpConnector.normalizeUrl(request.getContextPath());
113             if ("/".equals(path))
114             {
115                 path = HttpConnector.normalizeUrl(request.getServletPath());
116             }
117             else
118             {
119                 path = path + HttpConnector.normalizeUrl(request.getServletPath());
120             }
121 
122             String pathPart2 = uri.getAddress();
123 
124             if (!path.endsWith("/"))
125             {
126                 // "/foo" + "bar"
127                 path = path + HttpConnector.normalizeUrl(pathPart2);
128             }
129             else if (pathPart2.startsWith("/"))
130             {
131                 // "/foo/" + "/bar"
132                 path = path + pathPart2.substring(1);
133             }
134             else
135             {
136                 // "/foo/" + "bar"
137                 path = path + pathPart2;
138             }
139         }
140         else
141         {
142             // The Jetty transport has normal paths
143             path = HttpConnector.normalizeUrl(uri.getPath());
144         }
145 
146         requestMessage.setProperty(HttpConnector.HTTP_CONTEXT_PATH_PROPERTY, path, PropertyScope.INBOUND);
147 
148         // Call this to keep API compatability
149         setupRequestMessage(request, requestMessage);
150     }
151 
152 
153     protected void setupRequestMessage(HttpServletRequest request, MuleMessage requestMessage)
154     {
155         // template method
156     }
157 
158 
159     // The service() method cannot be overriden blindly as explained below.
160     //
161     // Until we use a version of the servlet spec that supports the PATCH method, we
162     // have to override service() nevertheless to avoid super's implementation
163     // barfing on a PATCH request.
164     @Override
165     protected void service(HttpServletRequest request, HttpServletResponse response)
166         throws ServletException, IOException
167     {
168         String method = request.getMethod();
169         if (method.equalsIgnoreCase(HttpConstants.METHOD_PATCH))
170         {
171             doAllMethods(request, response);
172         }
173         else
174         {
175             super.service(request, response);
176         }
177     }
178 
179     // We cannot override the service method and maintain MuleRESTServletReceiver
180     // functionality. See MULE-4806.
181 
182     @Override
183     protected void doGet(HttpServletRequest req, HttpServletResponse resp)
184         throws ServletException, IOException
185     {
186         doAllMethods(req, resp);
187     }
188 
189     @Override
190     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
191         throws ServletException, IOException
192     {
193         doAllMethods(req, resp);
194     }
195 
196     @Override
197     protected void doHead(HttpServletRequest req, HttpServletResponse resp)
198         throws ServletException, IOException
199     {
200         doAllMethods(req, resp);
201     }
202     @Override
203     protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
204         throws ServletException, IOException
205     {
206         doAllMethods(req, resp);
207     }
208 
209     @Override
210     protected void doPut(HttpServletRequest req, HttpServletResponse resp)
211         throws ServletException, IOException
212     {
213         doAllMethods(req, resp);
214     }
215     @Override
216     protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
217         throws ServletException, IOException
218     {
219         doAllMethods(req, resp);
220     }
221     @Override
222     protected void doTrace(HttpServletRequest req, HttpServletResponse resp)
223         throws ServletException, IOException
224     {
225         doAllMethods(req, resp);
226     }
227 
228     protected void doAllMethods(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
229     {
230         try
231         {
232             if (this.useCachedHttpServletRequest)
233             {
234                 request = new CachedHttpServletRequest(request);
235             }
236             MessageReceiver receiver = getReceiverForURI(request);
237 
238             MuleMessage requestMessage = receiver.createMuleMessage(request);
239             requestMessage.setProperty(HttpConnector.HTTP_METHOD_PROPERTY, request.getMethod(), PropertyScope.INBOUND);
240 
241             setupRequestMessage(request, requestMessage, receiver);
242 
243             MuleEvent event = routeMessage(receiver, requestMessage, request);
244             MuleMessage result = event == null ? null : event.getMessage();
245             writeResponse(response, result);
246         }
247         catch (Exception e)
248         {
249             handleException(e, ServletMessages.failedToProcessRequest().getMessage(), response);
250         }
251     }
252 
253     protected MuleEvent routeMessage(MessageReceiver receiver, MuleMessage requestMessage, HttpServletRequest request)
254             throws MuleException
255     {
256         return receiver.routeMessage(requestMessage);
257     }
258 
259     protected MessageReceiver getReceiverForURI(HttpServletRequest httpServletRequest)
260             throws EndpointException
261     {
262         String uri = getReceiverName(httpServletRequest);
263         if (uri == null)
264         {
265             throw new EndpointException(
266                     HttpMessages.unableToGetEndpointUri(httpServletRequest.getRequestURI()));
267         }
268 
269         MessageReceiver receiver = getReceivers().get(uri);
270 
271         // Lets see if the uri matches up with the last part of
272         // any of the receiver keys.
273         if (receiver == null)
274         {
275             receiver = HttpMessageReceiver.findReceiverByStem(connector.getReceivers(), uri);
276         }
277 
278         if (receiver == null)
279         {
280             receiver = matchReceiverByWildcard(uri, receiver);
281         }
282 
283         if (receiver == null)
284         {
285             throw new NoReceiverForEndpointException(uri);
286         }
287 
288         InboundEndpoint endpoint = receiver.getEndpoint();
289 
290         // Ensure that this receiver is using a dynamic (mutable) endpoint
291         if (!(endpoint instanceof DynamicURIInboundEndpoint))
292         {
293             endpoint = new DynamicURIInboundEndpoint(receiver.getEndpoint());
294             receiver.setEndpoint(endpoint);
295         }
296 
297         // Tell the dynamic endpoint about our new URL
298         //Note we don't use the servlet: prefix since we need to be dealing with the raw endpoint here
299         EndpointURI epURI = new MuleEndpointURI(getRequestUrl(httpServletRequest), muleContext);
300 
301         try
302         {
303             epURI.initialise();
304             epURI.getParams().setProperty("servlet.endpoint", "true");
305             ((DynamicURIInboundEndpoint) endpoint).setEndpointURI(epURI);
306         }
307         catch (InitialisationException e)
308         {
309             throw new EndpointException(e);
310         }
311         return receiver;
312     }
313 
314     protected MessageReceiver matchReceiverByWildcard(String uri, MessageReceiver receiver)
315     {
316         // Now match wild cards
317         for (Object key : getReceivers().keySet())
318         {
319             if (new WildcardFilter(key.toString()).accept(uri))
320             {
321                 receiver = connector.getReceivers().get(key);
322                 break;
323             }
324         }
325         return receiver;
326     }
327 
328     protected String getRequestUrl(HttpServletRequest httpServletRequest)
329     {
330         StringBuffer url = new StringBuffer();
331 
332         url.append(httpServletRequest.getScheme());
333         url.append("://");
334         url.append(httpServletRequest.getServerName());
335         url.append(":");
336         url.append(httpServletRequest.getServerPort());
337         url.append(httpServletRequest.getServletPath());
338 
339         String pathInfo = httpServletRequest.getPathInfo();
340         if (pathInfo != null)
341         {
342             url.append(pathInfo);
343         }
344 
345         String queryString = httpServletRequest.getQueryString();
346         if (queryString != null)
347         {
348             url.append("?");
349             url.append(queryString);
350         }
351         return url.toString();
352     }
353 
354     protected String getReceiverName(HttpServletRequest httpServletRequest)
355     {
356         String name = httpServletRequest.getPathInfo();
357         if (name == null)
358         {
359             name = httpServletRequest.getServletPath();
360             if (name == null)
361             {
362                 name = httpServletRequest.getParameter("endpoint");
363                 if (name == null)
364                 {
365                     Properties params = PropertiesUtils.getPropertiesFromQueryString(httpServletRequest.getQueryString());
366                     name = params.getProperty("endpoint");
367                     if (name == null)
368                     {
369                         return null;
370                     }
371                 }
372             }
373         }
374 
375         if (name.startsWith("/"))
376         {
377             name = name.substring(1);
378         }
379         return name;
380     }
381 
382     protected Map<Object, MessageReceiver> getReceivers()
383     {
384         return connector.getReceivers();
385     }
386 }