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
192 try
193 {
194 if (pollReply!=null)
195 {
196
197 if (_refsThreshold>0 && size==1 && transport instanceof JSONTransport)
198 {
199 MessageImpl message = (MessageImpl)messages.peek();
200
201
202 ByteBuffer buffer = message.getBuffer();
203 if (buffer!=null)
204 {
205 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
206 ((MessageImpl)message).decRef();
207 pollReply=null;
208 flushed=true;
209 }
210 else if (message.getRefs()>=_refsThreshold)
211 {
212 byte[] contentBytes = ("["+message.getJSON()+",{\""+Bayeux.SUCCESSFUL_FIELD+"\":true,\""+
213 Bayeux.CHANNEL_FIELD+"\":\""+Bayeux.META_CONNECT+"\"}]")
214 .getBytes(StringUtil.__UTF8);
215 int contentLength = contentBytes.length;
216
217 String headerString = "HTTP/1.1 200 OK\r\n"+
218 "Content-Type: text/json; charset=utf-8\r\n" +
219 "Content-Length: " + contentLength + "\r\n" +
220 "\r\n";
221
222 byte[] headerBytes = headerString.getBytes(StringUtil.__UTF8);
223
224 buffer = ByteBuffer.allocateDirect(headerBytes.length+contentLength);
225 buffer.put(headerBytes);
226 buffer.put(contentBytes);
227 buffer.flip();
228
229 message.setBuffer(buffer);
230 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
231 ((MessageImpl)message).decRef();
232 pollReply=null;
233 flushed=true;
234 }
235 }
236 }
237
238 if (!flushed)
239 {
240 Message message = null;
241 for (int i = 0;i<size;i++)
242 {
243 message=messages.getUnsafe(i);
244 message=_bayeux.extendSendClient(null, client, message);
245 if (message!=null)
246 transport.send(message);
247 }
248
249 if (pollReply!=null)
250 transport.send(pollReply);
251 transport.complete();
252 flushed=true;
253 }
254 }
255 finally
256 {
257 if (flushed)
258 messages.clear();
259 }
260 }
261
262 if (transport.resumePoll())
263 client.resume();
264 }
265 else if (transport!=null)
266 {
267 transport.complete();
268 }
269 }
270 }