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.Extension;
26 import org.cometd.Message;
27 import org.mortbay.cometd.AbstractBayeux;
28 import org.mortbay.cometd.AbstractCometdServlet;
29 import org.mortbay.cometd.ClientImpl;
30 import org.mortbay.cometd.JSONTransport;
31 import org.mortbay.cometd.MessageImpl;
32 import org.mortbay.cometd.Transport;
33 import org.mortbay.util.ArrayQueue;
34 import org.mortbay.util.StringUtil;
35 import org.mortbay.util.ajax.Continuation;
36 import org.mortbay.util.ajax.ContinuationSupport;
37
38
39
40
41
42
43
44 public class ContinuationCometdServlet extends AbstractCometdServlet
45 {
46
47 @Override
48 protected AbstractBayeux newBayeux()
49 {
50 return new ContinuationBayeux();
51 }
52
53
54 @Override
55 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
56 {
57
58 Object clientObj=request.getAttribute(CLIENT_ATTR);
59 ContinuationClient client=(clientObj instanceof ClientImpl)?(ContinuationClient)clientObj:null;
60 Transport transport=null;
61 boolean connect=false;
62 int received=-1;
63
64
65 if (client!=null)
66 {
67
68 transport=(Transport)request.getAttribute(TRANSPORT_ATTR);
69 transport.setResponse(response);
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=browserId(request);
96 if (browser_id==null)
97 browser_id=newBrowserId(request,response);
98
99 if (transport==null)
100 {
101 transport=_bayeux.newTransport(client,message);
102 transport.setResponse(response);
103 }
104 _bayeux.handle(null,transport,message);
105 message=null;
106
107 continue;
108 }
109 else
110 {
111 String browser_id=browserId(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 }
121
122
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 Message pollReply=null;
143
144 if (transport!=null)
145 {
146 pollReply=transport.getPollReply();
147 if (pollReply!=null)
148 {
149 if (_bayeux.isLogDebug())
150 _bayeux.logDebug("doPost: transport is polling");
151 long timeout=client.getTimeout();
152 if (timeout==0)
153 timeout=_bayeux.getTimeout();
154
155 Continuation continuation=ContinuationSupport.getContinuation(request,client);
156
157
158 synchronized (client)
159 {
160 if (!client.hasMessages() && !continuation.isPending()&& received<=1)
161 {
162
163 ((ContinuationClient)client).setContinuation(continuation);
164 request.setAttribute(CLIENT_ATTR,client);
165 request.setAttribute(TRANSPORT_ATTR,transport);
166 continuation.suspend(timeout);
167 }
168
169 if (!continuation.isPending())
170 client.access();
171
172 continuation.reset();
173 }
174
175 ((ContinuationClient)client).setContinuation(null);
176 transport.setPollReply(null);
177
178 for (Extension e:_bayeux.getExtensions())
179 pollReply=e.sendMeta(pollReply);
180 }
181 else if (client!=null)
182 {
183 client.access();
184 }
185 }
186
187
188 if (client!=null)
189 {
190
191 synchronized(client)
192 {
193 client.doDeliverListeners();
194 ArrayQueue<Message> messages= (ArrayQueue)client.getQueue();
195 int size=messages.size();
196
197 boolean flushed=false;
198 try
199 {
200 if (pollReply!=null)
201 {
202
203 if (_refsThreshold>0 && size==1 && transport instanceof JSONTransport)
204 {
205 MessageImpl message = (MessageImpl)messages.peek();
206
207
208 ByteBuffer buffer = message.getBuffer();
209 if (buffer!=null)
210 {
211 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
212 ((MessageImpl)message).decRef();
213 flushed=true;
214
215 }
216 else if (message.getRefs()>=_refsThreshold)
217 {
218 byte[] contentBytes = ("[{\""+Bayeux.SUCCESSFUL_FIELD+"\":true,\""+
219 Bayeux.CHANNEL_FIELD+"\":\""+Bayeux.META_CONNECT+"\"},"+
220 message.getJSON()+"]").getBytes(StringUtil.__UTF8);
221 int contentLength = contentBytes.length;
222
223 String headerString = "HTTP/1.1 200 OK\r\n"+
224 "Content-Type: text/json; charset=utf-8\r\n" +
225 "Content-Length: " + contentLength + "\r\n" +
226 "\r\n";
227
228 byte[] headerBytes = headerString.getBytes(StringUtil.__UTF8);
229
230 buffer = ByteBuffer.allocateDirect(headerBytes.length+contentLength);
231 buffer.put(headerBytes);
232 buffer.put(contentBytes);
233 buffer.flip();
234
235 message.setBuffer(buffer);
236 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
237 ((MessageImpl)message).decRef();
238 flushed=true;
239 }
240 else
241 transport.send(pollReply);
242 }
243 else
244 transport.send(pollReply);
245 }
246
247 if (!flushed)
248 {
249 Message message = null;
250 for (int i = 0;i<size;i++)
251 {
252 message=messages.getUnsafe(i);
253 transport.send(message);
254 }
255
256 transport.complete();
257 flushed=true;
258 }
259 }
260 finally
261 {
262 if (flushed)
263 messages.clear();
264 }
265 }
266
267 if (transport.resumePoll())
268 client.resume();
269 }
270 else if (transport!=null)
271 {
272 transport.complete();
273 }
274 }
275 }