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 ContinuationClient client=(clientObj instanceof ClientImpl)?(ContinuationClient)clientObj:null;
56 Transport transport=null;
57 boolean connect=false;
58 int received=-1;
59
60
61 if (client!=null)
62 {
63
64 transport=(Transport)request.getAttribute(TRANSPORT_ATTR);
65 transport.setResponse(response);
66 }
67 else
68 {
69 Message[] messages = getMessages(request);
70 received=messages.length;
71
72
73 String jsonpParam=request.getParameter("jsonp");
74
75
76 try
77 {
78 for (Message message : messages)
79 {
80 if (jsonpParam!=null)
81 message.put("jsonp",jsonpParam);
82
83 if (client==null)
84 {
85 client=(ContinuationClient)_bayeux.getClient((String)message.get(AbstractBayeux.CLIENT_FIELD));
86
87
88 if (client==null)
89 {
90
91 String browser_id=findBrowserId(request);
92 if (browser_id==null)
93 browser_id=setBrowserId(request,response);
94
95 if (transport==null)
96 {
97 transport=_bayeux.newTransport(client,message);
98 transport.setResponse(response);
99 }
100 _bayeux.handle(null,transport,message);
101 message=null;
102
103 continue;
104 }
105 else
106 {
107 String browser_id=findBrowserId(request);
108 if (browser_id!=null && (client.getBrowserId()==null || !client.getBrowserId().equals(browser_id)))
109 client.setBrowserId(browser_id);
110
111
112 if (transport==null)
113 {
114 transport=_bayeux.newTransport(client,message);
115 transport.setResponse(response);
116 }
117
118
119 if (!transport.resumePoll())
120 client.responsePending();
121 }
122 }
123
124 String channel=_bayeux.handle(client,transport,message);
125 connect|=AbstractBayeux.META_CONNECT.equals(channel);
126 }
127 }
128 finally
129 {
130 if (transport!=null && client!=null && !transport.resumePoll())
131 client.responded();
132
133 for (Message message : messages)
134 ((MessageImpl)message).decRef();
135 }
136 }
137
138 Message pollReply=null;
139
140 if (transport!=null)
141 {
142 pollReply=transport.getPollReply();
143 if (pollReply!=null)
144 {
145 if (_bayeux.isLogDebug())
146 _bayeux.logDebug("doPost: transport is polling");
147 long timeout=client.getTimeout();
148 if (timeout==0)
149 timeout=_bayeux.getTimeout();
150
151 Continuation continuation=ContinuationSupport.getContinuation(request,client);
152
153
154 synchronized (client)
155 {
156 if (!client.hasMessages() && !continuation.isPending()&& received<=1)
157 {
158
159 ((ContinuationClient)client).setContinuation(continuation);
160 request.setAttribute(CLIENT_ATTR,client);
161 request.setAttribute(TRANSPORT_ATTR,transport);
162 continuation.suspend(timeout);
163 }
164
165 if (!continuation.isPending())
166 client.access();
167
168 continuation.reset();
169 }
170
171 ((ContinuationClient)client).setContinuation(null);
172 transport.setPollReply(null);
173
174 pollReply=_bayeux.extendSendMeta(client,pollReply);
175 }
176 else if (client!=null)
177 {
178 client.access();
179 }
180 }
181
182
183 if (client!=null)
184 {
185 synchronized(client)
186 {
187 client.doDeliverListeners();
188 ArrayQueue<Message> messages= (ArrayQueue)client.getQueue();
189 int size=messages.size();
190 boolean flushed=false;
191 boolean shouldSendMessages= !( pollReply == null && client.isDeliverViaMetaConnectOnly() );
192
193 try
194 {
195 if (pollReply!=null)
196 {
197
198 if (_refsThreshold>0 && size==1 && transport instanceof JSONTransport)
199 {
200 MessageImpl message = (MessageImpl)messages.peek();
201
202
203 ByteBuffer buffer = message.getBuffer();
204 if (buffer!=null)
205 {
206 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
207 ((MessageImpl)message).decRef();
208 pollReply=null;
209 flushed=true;
210 }
211 else if (message.getRefs()>=_refsThreshold)
212 {
213 byte[] contentBytes = ("["+message.getJSON()+",{\""+Bayeux.SUCCESSFUL_FIELD+"\":true,\""+
214 Bayeux.CHANNEL_FIELD+"\":\""+Bayeux.META_CONNECT+"\"}]")
215 .getBytes(StringUtil.__UTF8);
216 int contentLength = contentBytes.length;
217
218 String headerString = "HTTP/1.1 200 OK\r\n"+
219 "Content-Type: text/json; charset=utf-8\r\n" +
220 "Content-Length: " + contentLength + "\r\n" +
221 "\r\n";
222
223 byte[] headerBytes = headerString.getBytes(StringUtil.__UTF8);
224
225 buffer = ByteBuffer.allocateDirect(headerBytes.length+contentLength);
226 buffer.put(headerBytes);
227 buffer.put(contentBytes);
228 buffer.flip();
229
230 message.setBuffer(buffer);
231 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
232 ((MessageImpl)message).decRef();
233 pollReply=null;
234 flushed=true;
235 }
236 }
237 }
238
239 if (!flushed)
240 {
241 if ( shouldSendMessages )
242 {
243 Message message = null;
244 for (int i = 0;i<size;i++)
245 {
246 message=messages.getUnsafe(i);
247 message=_bayeux.extendSendClient(null, client, message);
248 if (message!=null)
249 transport.send(message);
250 }
251 }
252 if (pollReply!=null)
253 {
254 transport.send(pollReply);
255 }
256 transport.complete();
257 flushed=true;
258 }
259 }
260 finally
261 {
262 if (flushed && shouldSendMessages)
263 messages.clear();
264 }
265 }
266
267 if (transport.resumePoll() || (client.isDeliverViaMetaConnectOnly() && pollReply == null))
268 client.resume();
269 }
270 else if (transport!=null)
271 {
272 transport.complete();
273 }
274 }
275 }