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.jetty;
8   
9   import org.mule.DefaultMuleEvent;
10  import org.mule.api.MessagingException;
11  import org.mule.api.MuleEvent;
12  import org.mule.api.MuleMessage;
13  import org.mule.api.transport.MessageReceiver;
14  import org.mule.api.transport.PropertyScope;
15  import org.mule.transport.http.HttpConnector;
16  
17  import java.io.IOException;
18  
19  import javax.servlet.ServletException;
20  import javax.servlet.http.HttpServletRequest;
21  import javax.servlet.http.HttpServletResponse;
22  
23  import org.mortbay.util.ajax.Continuation;
24  import org.mortbay.util.ajax.ContinuationSupport;
25  
26  public class JettyContinuationsReceiverServlet extends JettyReceiverServlet
27  {
28      // mutex used to make sure that the continuation is not resumed before it is suspended. 
29      private Object mutex = new Object();
30      
31      @Override
32      protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
33      {
34          try
35          {
36              MuleMessage responseMessage = null;
37              
38              synchronized (mutex)
39              {
40                  Continuation continuation = ContinuationSupport.getContinuation(request, mutex);
41                  
42                  if (!continuation.isPending())
43                  {
44                      // case where we are processing this request for the first time (suspend has not been called)
45                      
46                      MessageReceiver receiver = getReceiverForURI(request);
47                      
48                      MuleMessage requestMessage = receiver.createMuleMessage(request);
49                      requestMessage.setProperty(HttpConnector.HTTP_METHOD_PROPERTY, request.getMethod(), PropertyScope.INBOUND);
50      
51                      ContinuationsReplyTo continuationsReplyTo = new ContinuationsReplyTo(continuation, mutex);
52                      //This will allow Mule to continue the response once the service has do its processing
53                      requestMessage.setReplyTo(continuationsReplyTo);
54                      setupRequestMessage(request, requestMessage, receiver);
55                      
56                      if (receiver instanceof JettyHttpMessageReceiver)
57                      {
58                          //we force asynchronous in the {@link #routeMessage} method
59                          JettyHttpMessageReceiver jettyReceiver = (JettyHttpMessageReceiver) receiver;
60                          jettyReceiver.routeMessageAsync(requestMessage, continuationsReplyTo);
61                          
62                          // suspend indefinitely
63                          //TODO: perhaps we can make this configurable just like Http's keepSocketAlive is
64                          continuation.suspend(0L);
65                      }
66                      else
67                      {
68                          responseMessage = receiver.routeMessage(requestMessage).getMessage();
69                          writeResponse(response, responseMessage);
70                      }
71                  }
72                  else
73                  {
74                      // case where we are processing this request for the second time. 
75                      if (continuation.isResumed())
76                      {
77                          // the continuation was resumed so the response should be there
78                          Object r = continuation.getObject();
79                          // response object is either a MuleMessage of an Exception if there was an error
80                          if (r instanceof MuleMessage)
81                          {
82                              responseMessage = (MuleMessage) r;
83                              // clear the object because jetty reuses continuations for the same connection
84                              continuation.setObject(null);
85                              
86                              writeResponse(response, responseMessage);
87                          }
88                          else if (r instanceof Exception)
89                          {
90                              if (r instanceof MessagingException)
91                              {
92                                  // Reset access control on the MuleEvent because its message's owner is a different thread
93                                  // Otherwise when the message is modified during exception handling, it will fail
94                                  MessagingException me = (MessagingException) r;
95                                  MuleEvent event = me.getEvent();
96                                  if (event instanceof DefaultMuleEvent)
97                                  {
98                                      ((DefaultMuleEvent) event).resetAccessControl();
99                                  }
100                             }
101                             throw (Exception) r;
102                         }
103                     }
104                 }
105             }
106         }
107         catch (RuntimeException e)
108         {
109             // Jetty continuations throw a subclass of RuntimeException when suspend is don't treat them as errors
110             throw new ServletException(e);
111         }
112         catch (Exception e)
113         {
114             String message = e.getMessage();
115             handleException(e, message, response);
116         }
117     }
118 }