1   //========================================================================
2   //Copyright 2007 Mort Bay Consulting Pty. Ltd.
3   //------------------------------------------------------------------------
4   //Licensed under the Apache License, Version 2.0 (the "License");
5   //you may not use this file except in compliance with the License.
6   //You may obtain a copy of the License at 
7   //http://www.apache.org/licenses/LICENSE-2.0
8   //Unless required by applicable law or agreed to in writing, software
9   //distributed under the License is distributed on an "AS IS" BASIS,
10  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  //See the License for the specific language governing permissions and
12  //limitations under the License.
13  //========================================================================
14  
15  package org.mortbay.cometd.continuation;
16  
17  import java.io.IOException;
18  import java.util.List;
19  
20  import javax.servlet.ServletException;
21  import javax.servlet.http.HttpServletRequest;
22  import javax.servlet.http.HttpServletResponse;
23  
24  import org.mortbay.cometd.AbstractBayeux;
25  import org.mortbay.cometd.AbstractCometdServlet;
26  import org.mortbay.cometd.ClientImpl;
27  import org.mortbay.cometd.MessageImpl;
28  import org.mortbay.cometd.Transport;
29  import org.mortbay.util.ajax.Continuation;
30  import org.mortbay.util.ajax.ContinuationSupport;
31  
32  import dojox.cometd.Extension;
33  import dojox.cometd.Message;
34  
35  /* ------------------------------------------------------------ */
36  /**
37   * @author gregw
38   * @deprecated use {@link org.mortbay.cometd.SuspendingCometdServlet}
39   */
40  public class ContinuationCometdServlet extends AbstractCometdServlet
41  {
42      /* ------------------------------------------------------------ */
43      protected AbstractBayeux newBayeux()
44      {
45          return new ContinuationBayeux();
46      }
47  
48      /* ------------------------------------------------------------ */
49      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
50      {
51          doPost(req,resp);
52      }
53  
54      /* ------------------------------------------------------------ */
55      protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
56      {
57          // Look for an existing client and protect from context restarts
58          Object clientObj=req.getAttribute(CLIENT_ATTR);
59          ContinuationClient client=(clientObj instanceof ClientImpl)?(ContinuationClient)clientObj:null;
60          Transport transport=null;
61          boolean connect=false;
62          int num_msgs=-1;
63          
64          // Have we seen this request before
65          if (client!=null)
66          {
67              // yes - extract saved properties
68              transport=(Transport)req.getAttribute(TRANSPORT_ATTR);
69              transport.setResponse(resp);
70          }
71          else
72          {
73              Message[] messages = getMessages(req);
74              num_msgs=messages.length;
75  
76              /* check jsonp parameter */
77              String jsonpParam=req.getParameter("jsonp");
78  
79              // Handle all messages
80              try
81              {
82                  for (Message message : messages)
83                  {
84                      if (jsonpParam!=null)
85                          message.put("jsonp",jsonpParam);
86  
87                      if (client==null)
88                      {   
89                          client=(ContinuationClient)_bayeux.getClient((String)message.get(AbstractBayeux.CLIENT_FIELD));
90  
91                          // If no client,  SHOULD be a handshake, so force a transport and handle
92                          if (client==null)
93                          {
94                              // Setup a browser ID
95                              String browser_id=browserId(req);
96                              if (browser_id==null)
97                                  browser_id=newBrowserId(req,resp);
98  
99                              if (transport==null)
100                             {
101                                 transport=_bayeux.newTransport(client,message);
102                                 transport.setResponse(resp);
103                             }
104                             _bayeux.handle(null,transport,message);
105                             message=null;
106 
107                             continue;
108                         }
109                         else
110                         {
111                             String browser_id=browserId(req);
112                             if (browser_id!=null && (client.getBrowserId()==null || !client.getBrowserId().equals(browser_id)))
113                                 client.setBrowserId(browser_id);
114 
115                             // resolve transport
116                             if (transport==null)
117                             {
118                                 transport=_bayeux.newTransport(client,message);
119                                 transport.setResponse(resp);
120                             }
121 
122                             // Tell client to hold messages as a response is likely to be sent.
123                             if (!transport.resumePoll())
124                                 client.responsePending();
125                         }
126                     }
127 
128                     String channel=_bayeux.handle(client,transport,message);
129                     connect|=AbstractBayeux.META_CONNECT.equals(channel);
130                 }
131             }
132             finally
133             {
134                 if (transport!=null && client!=null && !transport.resumePoll())
135                     client.responded();
136                 
137                 for (Message message : messages)
138                     ((MessageImpl)message).decRef();
139             }
140         }
141 
142         // Do we need to wait for messages
143         if (transport!=null)
144         {
145             Message pollReply=transport.getPollReply();
146             if (pollReply!=null)
147             {
148                 if (_bayeux.isLogDebug())
149                     _bayeux.logDebug("doPost: transport is polling");
150                 long timeout=client.getTimeout();
151                 if (timeout==0)
152                     timeout=_bayeux.getTimeout();
153 
154                 Continuation continuation=ContinuationSupport.getContinuation(req,client);
155                 if (!continuation.isPending())
156                     client.access();
157 
158                 // Get messages or wait
159                 synchronized (client)
160                 {
161                     if (!client.hasMessages() && !continuation.isPending()&& num_msgs<=1)
162                     {
163                         // save state and suspend
164                         ((ContinuationClient)client).setContinuation(continuation);
165                         req.setAttribute(CLIENT_ATTR,client);
166                         req.setAttribute(TRANSPORT_ATTR,transport);
167                         continuation.suspend(timeout);
168                     }
169                     continuation.reset();
170                 }
171 
172                 ((ContinuationClient)client).setContinuation(null);
173                 transport.setPollReply(null);
174 
175                 for (Extension e:_bayeux.getExtensions())
176                     pollReply=e.sendMeta(pollReply);
177                 transport.send(pollReply);                 
178             }
179             else if (client!=null)
180             {
181                 client.access();
182             }
183         }
184 
185         // Send any messages.
186         if (client!=null) 
187         { 
188             List<Message> messages = null; 
189             Message message = null; 
190             synchronized(client)
191             {
192                 switch (client.getMessages())
193                 {
194                     case 0:
195                         break;
196                     case 1:
197                         message = client.takeMessage(); 
198                         break;
199                     default:
200                         messages = client.takeMessages(); 
201                         break;
202                 }
203                 
204                 if (!_asyncDeliver)
205                 {
206                     try
207                     {
208                         if (message!=null)
209                             transport.send(message); 
210                         else if (messages!=null)
211                             transport.send(messages); 
212                         
213                         transport.complete();
214                         resp.flushBuffer();
215 
216                         if (transport.resumePoll())
217                             client.resume();
218                         
219                         return;
220                     }
221                     catch(Throwable e)
222                     {
223                         // delivery failed!
224                         if (message!=null)
225                             client.returnMessage(message);
226                         else if (messages!=null)
227                             client.returnMessages(messages);
228                             
229                         if (e instanceof ServletException)
230                             throw (ServletException)e;
231                         if (e instanceof IOException)
232                             throw (IOException)e;
233                         if (e instanceof RuntimeException)
234                             throw (RuntimeException)e;
235                         if (e instanceof Error)
236                             throw (Error)e;
237                         if (e instanceof ThreadDeath)
238                             throw (ThreadDeath)e;
239                         throw new ServletException(e);
240                     }
241                 }
242             }
243             
244             if (message!=null)
245                 transport.send(message); 
246             else if (messages!=null)
247                 transport.send(messages); 
248             
249             if (transport.resumePoll())
250             	client.resume();
251         }
252         
253         if (transport!=null)
254             transport.complete();
255     }
256 }