View Javadoc

1   /*
2    * $Id: AbstractReceiverServlet.java 19191 2010-08-25 21:05:23Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.servlet;
12  
13  import org.mule.RequestContext;
14  import org.mule.api.MuleContext;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.config.MuleProperties;
17  import org.mule.api.lifecycle.InitialisationException;
18  import org.mule.api.transport.OutputHandler;
19  import org.mule.config.ExceptionHelper;
20  import org.mule.transport.http.HttpConstants;
21  import org.mule.transport.http.HttpResponse;
22  import org.mule.transport.http.transformers.MuleMessageToHttpResponse;
23  
24  import java.io.IOException;
25  
26  import javax.servlet.ServletException;
27  import javax.servlet.http.HttpServlet;
28  import javax.servlet.http.HttpServletResponse;
29  
30  import org.apache.commons.httpclient.Header;
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /**
35   * A base servlet used to receive requests from a servlet container and route
36   * them into Mule
37   */
38  
39  public abstract class AbstractReceiverServlet extends HttpServlet
40  {
41  
42      /**
43       * logger used by this class
44       */
45      protected transient Log logger = LogFactory.getLog(getClass());
46  
47      public static final String REQUEST_TIMEOUT_PROPERTY = "org.mule.servlet.timeout";
48      public static final String FEEDBACK_PROPERTY = "org.mule.servlet.feedback";
49      public static final String DEFAULT_CONTENT_TYPE_PROPERTY = "org.mule.servlet.default.content.type";
50  
51      /**
52       * The name of the servlet connector to use with this Servlet
53       * @deprecated Use {@link org.mule.transport.servlet.MuleServletContextListener#CONNECTOR_NAME} instead
54       */
55      @Deprecated
56      public static final String SERVLET_CONNECTOR_NAME_PROPERTY = "org.mule.servlet.connector.name";
57  
58      public static final String PAYLOAD_PARAMETER_NAME = "org.mule.servlet.payload.param";
59      public static final String DEFAULT_PAYLOAD_PARAMETER_NAME = "payload";
60  
61      public static final long DEFAULT_GET_TIMEOUT = 10000L;
62  
63      protected String payloadParameterName;
64      protected long timeout = DEFAULT_GET_TIMEOUT;
65      protected boolean feedback = true;
66      protected String defaultContentType = HttpConstants.DEFAULT_CONTENT_TYPE;
67      protected MuleContext muleContext;
68  
69      private MuleMessageToHttpResponse responseTransformer = new MuleMessageToHttpResponse();
70  
71      @Override
72      public final void init() throws ServletException
73      {
74          String timeoutString = getServletConfig().getInitParameter(REQUEST_TIMEOUT_PROPERTY);
75          if (timeoutString != null)
76          {
77              timeout = Long.parseLong(timeoutString);
78          }
79          if (logger.isInfoEnabled())
80          {
81              logger.info("Default request timeout for GET methods is: " + timeout);
82          }
83  
84          String feedbackString = getServletConfig().getInitParameter(FEEDBACK_PROPERTY);
85          if (feedbackString != null)
86          {
87              feedback = Boolean.valueOf(feedbackString);
88          }
89          if (logger.isInfoEnabled())
90          {
91              logger.info("feedback is set to: " + feedback);
92          }
93  
94          String ct = getServletConfig().getInitParameter(DEFAULT_CONTENT_TYPE_PROPERTY);
95          if (ct != null)
96          {
97              if (logger.isDebugEnabled())
98              {
99                  logger.debug("Using default content type configured on the servlet (" + DEFAULT_CONTENT_TYPE_PROPERTY + ") = " + ct);
100             }
101             defaultContentType = ct;
102         }
103         if (logger.isInfoEnabled())
104         {
105             logger.info("Default content type is: " + defaultContentType);
106         }
107 
108         payloadParameterName = getServletConfig().getInitParameter(PAYLOAD_PARAMETER_NAME);
109         if (payloadParameterName == null)
110         {
111             payloadParameterName = DEFAULT_PAYLOAD_PARAMETER_NAME;
112         }
113         if (logger.isInfoEnabled())
114         {
115             logger.info("Using payload param name: " + payloadParameterName);
116         }
117 
118         muleContext = setupMuleContext();
119         responseTransformer.setMuleContext(muleContext);
120         try
121         {
122             responseTransformer.initialise();
123         }
124         catch (InitialisationException e)
125         {
126             throw new ServletException(e);
127         }
128         doInit();
129     }
130 
131     protected MuleContext setupMuleContext() throws ServletException
132     {
133         MuleContext muleContext = (MuleContext) getServletContext().getAttribute(MuleProperties.MULE_CONTEXT_PROPERTY);
134         if (muleContext == null)
135         {
136             throw new ServletException("Property " + MuleProperties.MULE_CONTEXT_PROPERTY + " not set on ServletContext");
137         }
138         return muleContext;
139     }
140 
141     protected void doInit() throws ServletException
142     {
143         // template method
144     }
145 
146     protected void writeResponse(HttpServletResponse servletResponse, MuleMessage message) throws Exception
147     {
148         if (message == null)
149         {
150             servletResponse.setStatus(HttpServletResponse.SC_NO_CONTENT);
151             if (feedback)
152             {
153                 servletResponse.setStatus(HttpServletResponse.SC_OK);
154                 servletResponse.getWriter().write("Action was processed successfully. There was no result");
155             }
156         }
157         else
158         {
159             HttpResponse httpResponse;
160 
161             if (message.getPayload() instanceof HttpResponse)
162             {
163                 httpResponse = (HttpResponse) message.getPayload();
164 
165             }
166             else
167             {
168                 httpResponse = (HttpResponse) responseTransformer.transform(message);
169             }
170 
171             // Map the HttpResponse to the ServletResponse
172             Header contentTypeHeader = httpResponse.getFirstHeader(HttpConstants.HEADER_CONTENT_TYPE);
173             String contentType = defaultContentType;
174             if (contentTypeHeader != null && contentTypeHeader.getValue() != null)
175             {
176                 if (logger.isDebugEnabled())
177                 {
178                     logger.debug("Using Content-Type from message header = " + contentTypeHeader.getValue());
179                 }
180                 contentType = contentTypeHeader.getValue();
181             }
182 
183             servletResponse.setContentType(contentType);
184 
185             servletResponse = setHttpHeadersOnServletResponse(httpResponse, servletResponse);
186 
187             if (!servletResponse.isCommitted())
188             {
189                 servletResponse.setStatus(httpResponse.getStatusCode());
190             }
191 
192             if (httpResponse.hasBody())
193             {
194                 OutputHandler outputHandler = httpResponse.getBody();
195                 outputHandler.write(RequestContext.getEvent(), servletResponse.getOutputStream());
196             }
197         }
198         servletResponse.flushBuffer();
199     }
200 
201     protected HttpServletResponse setHttpHeadersOnServletResponse(HttpResponse httpResponse, HttpServletResponse servletResponse)
202     {
203         // Remove any Transfer-Encoding headers that were set (e.g. by MuleMessageToHttpResponse)
204         // earlier. Mule's default HTTP transformer is used in both cases: when the reply 
205         // MuleMessage is generated for our standalone HTTP server and for the servlet case. The 
206         // servlet container should be able to figure out the Transfer-Encoding itself and some 
207         // get confused by 
208         httpResponse.removeHeaders(HttpConstants.HEADER_TRANSFER_ENCODING);
209 
210         Header[] headers = httpResponse.getHeaders();
211         for (Header header : headers)
212         {
213             servletResponse.setHeader(header.getName(), header.getValue());
214         }
215         return servletResponse;
216     }
217 
218     protected void handleException(Throwable exception, String message, HttpServletResponse response)
219     {
220         logger.error("message: " + exception.getMessage(), exception);
221         int code = Integer.valueOf(ExceptionHelper.getErrorMapping("http", exception.getClass()));
222         response.setStatus(code);
223         try
224         {
225             response.sendError(code, message + ": " + exception.getMessage());
226         }
227         catch (IOException e)
228         {
229             logger.error("Failed to sendError on response: " + e.getMessage(), e);
230         }
231     }
232 }