1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.mortbay.cometd;
16
17 import java.io.FileNotFoundException;
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.InputStreamReader;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Map;
24 import javax.servlet.GenericServlet;
25 import javax.servlet.ServletException;
26 import javax.servlet.ServletRequest;
27 import javax.servlet.ServletResponse;
28 import javax.servlet.http.Cookie;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31
32 import org.cometd.Bayeux;
33 import org.cometd.DataFilter;
34 import org.cometd.Message;
35 import org.mortbay.cometd.filter.JSONDataFilter;
36 import org.mortbay.log.Log;
37 import org.mortbay.util.IO;
38 import org.mortbay.util.ajax.JSON;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public abstract class AbstractCometdServlet extends GenericServlet
117 {
118 public static final String CLIENT_ATTR="org.mortbay.cometd.client";
119 public static final String TRANSPORT_ATTR="org.mortbay.cometd.transport";
120 public static final String MESSAGE_PARAM="message";
121 public static final String TUNNEL_INIT_PARAM="tunnelInit";
122 public static final String HTTP_CLIENT_ID="BAYEUX_HTTP_CLIENT";
123 public final static String BROWSER_ID="BAYEUX_BROWSER";
124
125 protected AbstractBayeux _bayeux;
126 public final static int __DEFAULT_REFS_THRESHOLD=0;
127 protected int _refsThreshold=__DEFAULT_REFS_THRESHOLD;
128 protected boolean _jsonDebug;
129
130 public AbstractBayeux getBayeux()
131 {
132 return _bayeux;
133 }
134
135 protected abstract AbstractBayeux newBayeux();
136
137 @Override
138 public void init() throws ServletException
139 {
140 synchronized(AbstractCometdServlet.class)
141 {
142 _bayeux=(AbstractBayeux)getServletContext().getAttribute(Bayeux.ATTRIBUTE);
143 if (_bayeux == null)
144 {
145 _bayeux=newBayeux();
146 }
147 }
148
149 synchronized(_bayeux)
150 {
151 boolean was_initialized=_bayeux.isInitialized();
152 _bayeux.initialize(getServletContext());
153
154 if (!was_initialized)
155 {
156 String filters=getInitParameter("filters");
157 if (filters != null)
158 {
159 try
160 {
161 InputStream is=getServletContext().getResourceAsStream(filters);
162 if (is == null)
163 throw new FileNotFoundException(filters);
164
165 Object[] objects=(Object[])JSON.parse(new InputStreamReader(getServletContext().getResourceAsStream(filters),"utf-8"));
166 for (int i=0; objects != null && i < objects.length; i++)
167 {
168 Map<?,?> filter_def=(Map<?,?>)objects[i];
169
170 String fc=(String)filter_def.get("class");
171 if (fc != null)
172 Log.warn(filters + " file uses deprecated \"class\" name. Use \"filter\" instead");
173 else
174 fc=(String)filter_def.get("filter");
175 Class<?> c=Thread.currentThread().getContextClassLoader().loadClass(fc);
176 DataFilter filter=(DataFilter)c.newInstance();
177
178 if (filter instanceof JSONDataFilter)
179 ((JSONDataFilter)filter).init(filter_def.get("init"));
180
181 _bayeux.getChannel((String)filter_def.get("channels"),true).addDataFilter(filter);
182 }
183 }
184 catch(Exception e)
185 {
186 getServletContext().log("Could not parse: " + filters,e);
187 throw new ServletException(e);
188 }
189 }
190
191 String timeout=getInitParameter("timeout");
192 if (timeout != null)
193 _bayeux.setTimeout(Long.parseLong(timeout));
194
195 String maxInterval=getInitParameter("maxInterval");
196 if (maxInterval != null)
197 _bayeux.setMaxInterval(Long.parseLong(maxInterval));
198
199 String commentedJSON=getInitParameter("JSONCommented");
200 _bayeux.setJSONCommented(commentedJSON != null && Boolean.parseBoolean(commentedJSON));
201
202 String l=getInitParameter("logLevel");
203 if (l != null && l.length() > 0)
204 _bayeux.setLogLevel(Integer.parseInt(l));
205
206 String interval=getInitParameter("interval");
207 if (interval != null)
208 _bayeux.setInterval(Long.parseLong(interval));
209
210 String maxLazy=getInitParameter("maxLazyLatency");
211 if (maxLazy != null)
212 _bayeux.setMaxLazyLatency(Integer.parseInt(maxLazy));
213
214 String mfInterval=getInitParameter("multiFrameInterval");
215 if (mfInterval != null)
216 _bayeux.setMultiFrameInterval(Integer.parseInt(mfInterval));
217
218 String requestAvailable=getInitParameter("requestAvailable");
219 _bayeux.setRequestAvailable(requestAvailable != null && Boolean.parseBoolean(requestAvailable));
220
221 String async=getInitParameter("asyncDeliver");
222 if (async != null)
223 getServletContext().log("asyncDeliver no longer supported");
224
225 String refsThreshold=getInitParameter("refsThreshold");
226 if (refsThreshold != null)
227 _refsThreshold=Integer.parseInt(refsThreshold);
228
229 String jsonDebugParam=getInitParameter("jsonDebug");
230 _jsonDebug=Boolean.parseBoolean(jsonDebugParam);
231
232 String channelIdCacheLimit=getInitParameter("channelIdCacheLimit");
233 if (channelIdCacheLimit != null)
234 _bayeux.setChannelIdCacheLimit(Integer.parseInt(channelIdCacheLimit));
235
236 _bayeux.generateAdvice();
237
238 if (_bayeux.isLogInfo())
239 {
240 getServletContext().log("timeout=" + timeout);
241 getServletContext().log("interval=" + interval);
242 getServletContext().log("maxInterval=" + maxInterval);
243 getServletContext().log("multiFrameInterval=" + mfInterval);
244 getServletContext().log("filters=" + filters);
245 getServletContext().log("refsThreshold=" + refsThreshold);
246 }
247 }
248 }
249
250 getServletContext().setAttribute(Bayeux.ATTRIBUTE,_bayeux);
251 }
252
253 protected abstract void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
254
255 @Override
256 public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException
257 {
258 HttpServletRequest request=(HttpServletRequest)req;
259 HttpServletResponse response=(HttpServletResponse)resp;
260
261 if (_bayeux.isRequestAvailable())
262 _bayeux.setCurrentRequest(request);
263 try
264 {
265 service(request,response);
266 }
267 finally
268 {
269 if (_bayeux.isRequestAvailable())
270 _bayeux.setCurrentRequest(null);
271 }
272 }
273
274 protected String findBrowserId(HttpServletRequest request)
275 {
276 Cookie[] cookies=request.getCookies();
277 if (cookies != null)
278 {
279 for (Cookie cookie : cookies)
280 {
281 if (BROWSER_ID.equals(cookie.getName()))
282 return cookie.getValue();
283 }
284 }
285
286 return null;
287 }
288
289 protected String setBrowserId(HttpServletRequest request, HttpServletResponse response)
290 {
291 String browser_id=Long.toHexString(request.getRemotePort()) + Long.toString(_bayeux.getRandom(),36) + Long.toString(System.currentTimeMillis(),36)
292 + Long.toString(request.getRemotePort(),36);
293
294 Cookie cookie=new Cookie(BROWSER_ID,browser_id);
295 cookie.setPath("/");
296 cookie.setMaxAge(-1);
297 response.addCookie(cookie);
298 return browser_id;
299 }
300
301 private static Message[] __EMPTY_BATCH=new Message[0];
302
303 protected Message[] getMessages(HttpServletRequest request) throws IOException, ServletException
304 {
305 String messageString=null;
306 try
307 {
308
309 if (request.getContentType() != null && !request.getContentType().startsWith("application/x-www-form-urlencoded"))
310 {
311 if (_jsonDebug)
312 {
313 messageString=IO.toString(request.getReader());
314 return _bayeux.parse(messageString);
315 }
316 return _bayeux.parse(request.getReader());
317 }
318
319 String[] batches=request.getParameterValues(MESSAGE_PARAM);
320
321 if (batches == null || batches.length == 0)
322 return __EMPTY_BATCH;
323
324 if (batches.length == 1)
325 {
326 messageString=batches[0];
327 return _bayeux.parse(messageString);
328 }
329
330 List<Message> messages=new ArrayList<Message>();
331 for (String batch : batches)
332 {
333 if (batch == null)
334 continue;
335 messageString = batch;
336 _bayeux.parseTo(messageString, messages);
337 }
338 return messages.toArray(new Message[messages.size()]);
339 }
340 catch(IOException x)
341 {
342 throw x;
343 }
344 catch(Exception x)
345 {
346 return handleJSONParseException(request, messageString, x);
347 }
348 }
349
350
351
352
353
354
355
356
357
358
359
360
361 protected Message[] handleJSONParseException(HttpServletRequest request, String messageString, Exception x) throws ServletException
362 {
363 Log.getLogger("org.cometd.json").warn("Exception parsing JSON: " + messageString, x);
364 throw new ServletException("Exception parsing JSON: |"+messageString+"|", x);
365 }
366 }