1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.cometd;
16 import java.io.IOException;
17 import java.nio.ByteBuffer;
18
19 import javax.servlet.ServletException;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
22
23 import org.cometd.Bayeux;
24 import org.cometd.Extension;
25 import org.cometd.Message;
26 import org.mortbay.util.ArrayQueue;
27 import org.mortbay.util.StringUtil;
28
29 public class SuspendingCometdServlet extends AbstractCometdServlet
30 {
31
32 protected AbstractBayeux newBayeux()
33 {
34 return new SuspendingBayeux();
35 }
36
37
38 public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
39 {
40
41 SuspendingClient client=null;
42 Transport transport=null;
43 boolean connect=false;
44 int received=-1;
45
46
47 boolean initial=false;
48 if (request.isInitial() || request.getAttribute(CLIENT_ATTR)==null)
49 {
50 initial=true;
51
52 Message[] messages = getMessages(request);
53 received=messages.length;
54
55
56 String jsonpParam=request.getParameter("jsonp");
57
58
59 boolean response_pending=false;
60 try
61 {
62 for (Message message : messages)
63 {
64 if (jsonpParam!=null)
65 message.put("jsonp",jsonpParam);
66
67 if (client==null)
68 {
69 client=(SuspendingClient)_bayeux.getClient((String)message.get(AbstractBayeux.CLIENT_FIELD));
70
71
72 if (client==null)
73 {
74
75 String browser_id=browserId(request);
76 if (browser_id==null)
77 browser_id=newBrowserId(request,response);
78
79 if (transport==null)
80 {
81 transport=_bayeux.newTransport(client,message);
82 transport.setResponse(response);
83 }
84 _bayeux.handle(null,transport,message);
85 message=null;
86
87 continue;
88 }
89 else
90 {
91 String browser_id=browserId(request);
92 if (browser_id!=null && (client.getBrowserId()==null || !client.getBrowserId().equals(browser_id)))
93 client.setBrowserId(browser_id);
94
95
96 if (transport==null)
97 {
98 transport=_bayeux.newTransport(client,message);
99 transport.setResponse(response);
100 }
101
102
103 if (!transport.resumePoll())
104 {
105 response_pending=true;
106 client.responsePending();
107 }
108 }
109 }
110
111 String channel=_bayeux.handle(client,transport,message);
112 connect|=AbstractBayeux.META_CONNECT.equals(channel);
113 }
114 }
115 finally
116 {
117 if (response_pending)
118 client.responded();
119
120 for (Message message : messages)
121 ((MessageImpl)message).decRef();
122 }
123 }
124 else
125 {
126 transport=(Transport)request.getAttribute(TRANSPORT_ATTR);
127 transport.setResponse(response);
128 Object clientObj=request.getAttribute(CLIENT_ATTR);
129 client=(clientObj instanceof ClientImpl)?(SuspendingClient)clientObj:null;
130 if (client!=null)
131 client.setPollRequest(null);
132 }
133
134 Message pollReply=null;
135
136 if (transport!=null)
137 {
138 pollReply=transport.getPollReply();
139 if (pollReply!=null)
140 {
141 if (_bayeux.isLogDebug())
142 _bayeux.logDebug("doPost: transport is polling");
143 long timeout=client.getTimeout();
144 if (timeout==0)
145 timeout=_bayeux.getTimeout();
146
147
148 synchronized (client)
149 {
150 if (!client.hasMessages() && initial && received<=1)
151 {
152
153 request.suspend(timeout);
154 client.setPollRequest(request);
155 request.setAttribute(CLIENT_ATTR,client);
156 request.setAttribute(TRANSPORT_ATTR,transport);
157 return;
158 }
159
160 if (initial)
161 client.access();
162 }
163
164 transport.setPollReply(null);
165
166 for (Extension e:_bayeux.getExtensions())
167 pollReply=e.sendMeta(pollReply);
168 }
169 else if (client!=null)
170 {
171 client.access();
172 }
173 }
174
175
176
177 if (client!=null)
178 {
179 synchronized(client)
180 {
181 ArrayQueue<Message> messages= (ArrayQueue)client.getQueue();
182 int size=messages.size();
183 boolean flushed=false;
184
185 try
186 {
187 if (pollReply!=null)
188 {
189
190 if (_refsThreshold>0 && size==1 && transport instanceof JSONTransport)
191 {
192 MessageImpl message = (MessageImpl)messages.peek();
193
194
195 ByteBuffer buffer = message.getBuffer();
196 if (buffer != null )
197 {
198 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
199 ((MessageImpl)message).decRef();
200 flushed=true;
201 }
202 else if (message.getRefs()>=_refsThreshold)
203 {
204
205 byte[] contentBytes = ("[{\""+Bayeux.SUCCESSFUL_FIELD+"\":true,\""+
206 Bayeux.CHANNEL_FIELD+"\":\""+Bayeux.META_CONNECT+"\"},"+
207 message.getJSON()+"]").getBytes(StringUtil.__UTF8);
208 int contentLength = contentBytes.length;
209
210 String headerString = "HTTP/1.1 200 OK\r\n"+
211 "Content-Type: text/json; charset=utf-8\r\n" +
212 "Content-Length: " + contentLength + "\r\n" +
213 "\r\n";
214
215 byte[] headerBytes = headerString.getBytes(StringUtil.__UTF8);
216
217 buffer = ByteBuffer.allocateDirect(headerBytes.length+contentLength);
218 buffer.put(headerBytes);
219 buffer.put(contentBytes);
220 buffer.flip();
221 message.setBuffer(buffer);
222
223 request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
224 ((MessageImpl)message).decRef();
225 flushed=true;
226 }
227 else
228 transport.send(pollReply);
229 }
230 else
231 transport.send(pollReply);
232 }
233
234 if (!flushed)
235 {
236 Message message = null;
237 for (int i=0;i<size;i++)
238 {
239 message=messages.getUnsafe(i);
240 transport.send(message);
241 }
242
243 transport.complete();
244 flushed=true;
245 }
246 }
247 finally
248 {
249 if (flushed)
250 messages.clear();
251 }
252 }
253
254 if (transport.resumePoll())
255 client.resume();
256 }
257 else if (transport!=null)
258 {
259 transport.complete();
260 }
261 }
262 }