1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.cometd.continuation;
16
17 import java.io.IOException;
18 import java.nio.ByteBuffer;
19
20 import javax.servlet.ServletException;
21 import javax.servlet.http.HttpServletRequest;
22 import javax.servlet.http.HttpServletResponse;
23
24 import org.cometd.Bayeux;
25 import org.cometd.Client;
26 import org.cometd.Extension;
27 import org.cometd.Message;
28 import org.mortbay.cometd.AbstractBayeux;
29 import org.mortbay.cometd.AbstractCometdServlet;
30 import org.mortbay.cometd.ClientImpl;
31 import org.mortbay.cometd.JSONTransport;
32 import org.mortbay.cometd.MessageImpl;
33 import org.mortbay.cometd.Transport;
34 import org.mortbay.util.ArrayQueue;
35 import org.mortbay.util.StringUtil;
36 import org.mortbay.util.ajax.Continuation;
37 import org.mortbay.util.ajax.ContinuationSupport;
38
39
40 public class ContinuationCometdServlet extends AbstractCometdServlet
41 {
42
43 @Override
44 protected AbstractBayeux newBayeux()
45 {
46 return new ContinuationBayeux();
47 }
48
49
50 @Override
51 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
52 {
53
54 Object clientObj=request.getAttribute(CLIENT_ATTR);
55 Transport transport=null;
56 int received=-1;
57 boolean metaConnectDeliveryOnly=false;
58 boolean pendingResponse=false;
59 boolean metaConnect=false;
60
61
62 ContinuationClient client=(clientObj instanceof ClientImpl)?(ContinuationClient)clientObj:null;
63 if (client!=null)
64 {
65
66 transport=(Transport)request.getAttribute(TRANSPORT_ATTR);
67 transport.setResponse(response);
68 metaConnectDeliveryOnly=client.isMetaConnectDeliveryOnly() || transport.isMetaConnectDeliveryOnly();
69 metaConnect=true;
70 }
71 else
72 {
73 Message[] messages = getMessages(request);
74 received=messages.length;
75
76
77 String jsonpParam=request.getParameter("jsonp");
78
79
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
92 if (client==null)
93 {
94
95 String browser_id=findBrowserId(request);
96 if (browser_id==null)
97 browser_id=setBrowserId(request,response);
98
99 if (transport==null)
100 {
101 transport=_bayeux.newTransport(client,message);
102 transport.setResponse(response);
103 metaConnectDeliveryOnly=transport.isMetaConnectDeliveryOnly();
104 }
105 _bayeux.handle(null,transport,message);
106 message=null;
107 continue;
108 }
109 }
110
111 String browser_id=findBrowserId(request);
112 if (browser_id!=null && (client.getBrowserId()==null || !client.getBrowserId().equals(browser_id)))
113 client.setBrowserId(browser_id);
114
115
116 if (transport==null)
117 {
118 transport=_bayeux.newTransport(client,message);
119 transport.setResponse(response);
120 metaConnectDeliveryOnly=client.isMetaConnectDeliveryOnly() || transport.isMetaConnectDeliveryOnly();
121 }
122
123
124 if (!metaConnectDeliveryOnly && !pendingResponse)
125 {
126 pendingResponse=true;
127 client.responsePending();
128 }
129
130 if (Bayeux.META_CONNECT.equals(message.getChannel()))
131 metaConnect=true;
132
133 _bayeux.handle(client,transport,message);
134 }
135 }
136 finally
137 {
138 for (Message message : messages)
139 ((MessageImpl)message).decRef();
140 if (pendingResponse)
141 {
142 client.responded();
143 }
144 }
145 }
146
147 Message metaConnectReply=null;
148
149
150 if (transport!=null)
151 {
152 metaConnectReply=transport.getMetaConnectReply();
153 if (metaConnectReply!=null)
154 {
155 long timeout=client.getTimeout();
156 if (timeout==0)
157 timeout=_bayeux.getTimeout();
158
159 Continuation continuation=ContinuationSupport.getContinuation(request,client);
160
161
162 synchronized (client)
163 {
164 if (!client.hasNonLazyMessages() && !continuation.isPending()&& received<=1)
165 {
166
167 ((ContinuationClient)client).setContinuation(continuation);
168 request.setAttribute(CLIENT_ATTR,client);
169 request.setAttribute(TRANSPORT_ATTR,transport);
170 continuation.suspend(timeout);
171 }
172
173 if (!continuation.isPending())
174 client.access();
175
176 continuation.reset();
177 }
178
179 ((ContinuationClient)client).setContinuation(null);
180 transport.setMetaConnnectReply(null);
181
182 }
183 else if (client!=null)
184 {
185 client.access();
186 }
187 }
188
189 if (client!=null)
190 {
191 if (metaConnectDeliveryOnly && !metaConnect)
192 {
193
194 client.resume();
195 }
196 else
197 {
198
199 synchronized(client)
200 {
201 client.doDeliverListeners();
202
203 final ArrayQueue<Message> messages= (ArrayQueue)client.getQueue();
204 final int size=messages.size();
205
206 try
207 {
208 for (int i=0;i<size;i++)
209 {
210 final Message message=messages.getUnsafe(i);
211 final MessageImpl mesgImpl=(message instanceof MessageImpl)?(MessageImpl)message:null;
212
213
214 if (i==0 && size==1 && mesgImpl!=null && _refsThreshold>0 && metaConnectReply!=null && transport instanceof JSONTransport)
215 {
216
217 ByteBuffer buffer = mesgImpl.getBuffer();
218 if (buffer!=null)
219 {
220
221 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
222 if (metaConnectReply instanceof MessageImpl)
223 ((MessageImpl)metaConnectReply).decRef();
224 metaConnectReply=null;
225 transport=null;
226 mesgImpl.decRef();
227 continue;
228 }
229 else if (mesgImpl.getRefs()>=_refsThreshold)
230 {
231
232 byte[] contentBytes = ("["+mesgImpl.getJSON()+",{\""+Bayeux.SUCCESSFUL_FIELD+"\":true,\""+
233 Bayeux.CHANNEL_FIELD+"\":\""+Bayeux.META_CONNECT+"\"}]")
234 .getBytes(StringUtil.__UTF8);
235 int contentLength = contentBytes.length;
236
237 String headerString = "HTTP/1.1 200 OK\r\n"+
238 "Content-Type: text/json; charset=utf-8\r\n" +
239 "Content-Length: " + contentLength + "\r\n" +
240 "\r\n";
241
242 byte[] headerBytes = headerString.getBytes(StringUtil.__UTF8);
243
244 buffer = ByteBuffer.allocateDirect(headerBytes.length+contentLength);
245 buffer.put(headerBytes);
246 buffer.put(contentBytes);
247 buffer.flip();
248
249 mesgImpl.setBuffer(buffer);
250 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
251 metaConnectReply=null;
252 if (metaConnectReply instanceof MessageImpl)
253 ((MessageImpl)metaConnectReply).decRef();
254 transport=null;
255 mesgImpl.decRef();
256 continue;
257 }
258 }
259
260 if (message!=null)
261 transport.send(message);
262 if (mesgImpl!=null)
263 mesgImpl.decRef();
264 }
265 }
266 finally
267 {
268 messages.clear();
269 }
270 }
271
272 if (metaConnectReply!=null)
273 {
274 metaConnectReply=_bayeux.extendSendMeta(client,metaConnectReply);
275 transport.send(metaConnectReply);
276 if (metaConnectReply instanceof MessageImpl)
277 ((MessageImpl)metaConnectReply).decRef();
278 }
279 }
280 }
281
282 if (transport!=null)
283 transport.complete();
284 }
285
286 public void destroy()
287 {
288 if (_bayeux!=null)
289 ((ContinuationBayeux)_bayeux).destroy();
290 }
291 }