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 if (transport!=null)
150 {
151 metaConnectReply=transport.getMetaConnectReply();
152 if (metaConnectReply!=null)
153 {
154 long timeout=client.getTimeout();
155 if (timeout==0)
156 timeout=_bayeux.getTimeout();
157
158 Continuation continuation=ContinuationSupport.getContinuation(request,client);
159
160
161 synchronized (client)
162 {
163 if (!client.hasMessages() && !continuation.isPending()&& received<=1)
164 {
165
166 ((ContinuationClient)client).setContinuation(continuation);
167 request.setAttribute(CLIENT_ATTR,client);
168 request.setAttribute(TRANSPORT_ATTR,transport);
169 continuation.suspend(timeout);
170 }
171
172 if (!continuation.isPending())
173 client.access();
174
175 continuation.reset();
176 }
177
178 ((ContinuationClient)client).setContinuation(null);
179 transport.setMetaConnnectReply(null);
180
181 }
182 else if (client!=null)
183 {
184 client.access();
185 }
186 }
187
188
189 if (client!=null && (!metaConnectDeliveryOnly || metaConnect))
190 {
191 synchronized(client)
192 {
193 client.doDeliverListeners();
194
195 final ArrayQueue<Message> messages= (ArrayQueue)client.getQueue();
196 final int size=messages.size();
197
198 try
199 {
200 for (int i=0;i<size;i++)
201 {
202 final Message message=messages.getUnsafe(i);
203 final MessageImpl mesgImpl=(message instanceof MessageImpl)?(MessageImpl)message:null;
204
205
206 if (i==0 && size==1 && mesgImpl!=null && _refsThreshold>0 && metaConnectReply!=null && transport instanceof JSONTransport)
207 {
208
209 ByteBuffer buffer = mesgImpl.getBuffer();
210 if (buffer!=null)
211 {
212
213 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
214 if (metaConnectReply instanceof MessageImpl)
215 ((MessageImpl)metaConnectReply).decRef();
216 metaConnectReply=null;
217 transport=null;
218 mesgImpl.decRef();
219 continue;
220 }
221 else if (mesgImpl.getRefs()>=_refsThreshold)
222 {
223
224 byte[] contentBytes = ("["+mesgImpl.getJSON()+",{\""+Bayeux.SUCCESSFUL_FIELD+"\":true,\""+
225 Bayeux.CHANNEL_FIELD+"\":\""+Bayeux.META_CONNECT+"\"}]")
226 .getBytes(StringUtil.__UTF8);
227 int contentLength = contentBytes.length;
228
229 String headerString = "HTTP/1.1 200 OK\r\n"+
230 "Content-Type: text/json; charset=utf-8\r\n" +
231 "Content-Length: " + contentLength + "\r\n" +
232 "\r\n";
233
234 byte[] headerBytes = headerString.getBytes(StringUtil.__UTF8);
235
236 buffer = ByteBuffer.allocateDirect(headerBytes.length+contentLength);
237 buffer.put(headerBytes);
238 buffer.put(contentBytes);
239 buffer.flip();
240
241 mesgImpl.setBuffer(buffer);
242 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
243 metaConnectReply=null;
244 if (metaConnectReply instanceof MessageImpl)
245 ((MessageImpl)metaConnectReply).decRef();
246 transport=null;
247 mesgImpl.decRef();
248 continue;
249 }
250 }
251
252 if (message!=null)
253 transport.send(message);
254 if (mesgImpl!=null)
255 mesgImpl.decRef();
256 }
257 }
258 finally
259 {
260 messages.clear();
261 }
262 }
263
264 if (metaConnectReply!=null)
265 {
266 metaConnectReply=_bayeux.extendSendMeta(client,metaConnectReply);
267 transport.send(metaConnectReply);
268 if (metaConnectReply instanceof MessageImpl)
269 ((MessageImpl)metaConnectReply).decRef();
270 }
271 }
272
273 if (transport!=null)
274 transport.complete();
275 }
276 }