1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.acme;
17
18 import java.io.IOException;
19 import java.util.ArrayList;
20 import java.util.HashMap;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Map;
24
25 import javax.servlet.FilterChain;
26 import javax.servlet.FilterConfig;
27 import javax.servlet.ServletException;
28 import javax.servlet.ServletRequest;
29 import javax.servlet.ServletResponse;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpSession;
32
33 import org.mortbay.util.ajax.AjaxFilter;
34 import org.mortbay.util.ajax.Continuation;
35 import org.mortbay.util.ajax.ContinuationSupport;
36
37
38
39
40
41 public class ChatFilter extends AjaxFilter
42 {
43 private Map chatrooms;
44
45
46
47
48
49
50 public void init(FilterConfig filterConfig) throws ServletException
51 {
52 super.init(filterConfig);
53 chatrooms=new HashMap();
54 }
55
56
57
58
59
60 public void destroy()
61 {
62 super.destroy();
63 chatrooms.clear();
64 chatrooms=null;
65 }
66
67
68
69 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
70 {
71 HttpSession session = ((HttpServletRequest)request).getSession(true);
72 super.doFilter(request,response,chain);
73 }
74
75
76
77
78
79 public void handle(String method, String message, HttpServletRequest request, AjaxResponse response)
80 {
81 request.getSession(true);
82
83 String roomName=request.getParameter("room");
84 if (roomName==null)
85 roomName="0";
86 Map room = null;
87 synchronized(this)
88 {
89 room=(Map)chatrooms.get(roomName);
90 if (room==null)
91 {
92 room=new HashMap();
93 chatrooms.put(roomName,room);
94 }
95 }
96
97 if ("join".equals(method))
98 doJoinChat(room,message,request, response);
99 else if ("chat".equals(method))
100 doChat(room,message,request,response);
101 else if ("poll".equals(method))
102 doPoll(room,request,response);
103 else if ("leave".equals(method))
104 doLeaveChat(room,message,request,response);
105 else
106 super.handle(method, message,request, response);
107 }
108
109
110 private void doJoinChat(Map room, String name, HttpServletRequest request, AjaxResponse response)
111 {
112 HttpSession session = request.getSession(true);
113 String id = session.getId();
114 if (name==null || name.length()==0)
115 name="Newbie";
116 Member member=null;
117
118 synchronized (room)
119 {
120 member=(Member)room.get(id);
121 if (member==null)
122 {
123 member = new Member(session,name);
124 room.put(session.getId(),member);
125 }
126 else
127 member.setName(name);
128
129
130 sendMessage(room,member,"has joined the chat",true);
131
132
133 sendMembers(room,response);
134 }
135 }
136
137
138
139 private void doLeaveChat(Map room, String name, HttpServletRequest request, AjaxResponse response)
140 {
141 HttpSession session = request.getSession(true);
142 String id = session.getId();
143
144 Member member=null;
145 synchronized (room)
146 {
147 member = (Member)room.get(id);
148 if (member==null)
149 return;
150 if ("Elvis".equals(member.getName()))
151 sendMessage(room,member,"has left the building",true);
152 else
153 sendMessage(room,member,"has left the chat",true);
154 room.remove(id);
155 member.setName(null);
156 }
157
158 sendMembers(room,response);
159 }
160
161
162
163 private void doChat(Map room, String text, HttpServletRequest request, AjaxResponse response)
164 {
165 HttpSession session = request.getSession(true);
166 String id = session.getId();
167
168 Member member=null;
169 synchronized (room)
170 {
171 member = (Member)room.get(id);
172
173 if (member==null)
174 return;
175 sendMessage(room, member, text, false);
176 }
177 }
178
179
180
181 private void doPoll(Map room, HttpServletRequest request, AjaxResponse response)
182 {
183 HttpSession session = request.getSession(true);
184 String id = session.getId();
185 long timeoutMS = 60000L;
186 if (request.getParameter("timeout")!=null)
187 timeoutMS=Long.parseLong(request.getParameter("timeout"));
188 if (session.isNew())
189 timeoutMS=1;
190
191 Member member=null;
192 synchronized (room)
193 {
194 member = (Member)room.get(id);
195 if (member==null)
196 {
197 member = new Member(session,null);
198 room.put(session.getId(),member);
199 }
200
201 Continuation continuation = ContinuationSupport.getContinuation(request, room);
202
203 if (!member.hasMessages())
204 {
205 if (member.getContinuation()!=null && member.getContinuation()!=continuation)
206 {
207
208 Message duplicate = new Message("System","Multiple frames/tabs/windows from same browser!",true);
209 Message action = new Message("System","Please use only one frame/tab/window",true);
210 member.addMessage(duplicate);
211 member.addMessage(action);
212 try
213 {
214 Thread.sleep(5000);
215 }
216 catch(Exception e)
217 {}
218 }
219 else
220 {
221 member.setContinuation(continuation);
222 continuation.suspend(timeoutMS);
223 }
224 }
225
226 if (member.getContinuation()==continuation)
227 member.setContinuation(null);
228
229
230 if (member.sendMessages(response))
231 sendMembers(room,response);
232 }
233
234 }
235
236
237 private void sendMessage(Map room, Member member, String text, boolean alert)
238 {
239 Message event=new Message(member.getName(),text,alert);
240
241 ArrayList invalids=null;
242 synchronized (room)
243 {
244 Iterator iter = room.values().iterator();
245 while (iter.hasNext())
246 {
247 Member m = (Member)iter.next();
248
249 try
250 {
251 m.getSession().getAttribute("anything");
252 m.addMessage(event);
253 }
254 catch(IllegalStateException e)
255 {
256 if (invalids==null)
257 invalids=new ArrayList();
258 invalids.add(m);
259 iter.remove();
260 }
261 }
262 }
263
264 for (int i=0;invalids!=null && i<invalids.size();i++)
265 {
266 Member m = (Member)invalids.get(i);
267 sendMessage(room,m,"has timed out of the chat",true);
268 }
269 }
270
271 private void sendMembers(Map room, AjaxResponse response)
272 {
273 StringBuffer buf = new StringBuffer();
274 buf.append("<ul>\n");
275 synchronized (room)
276 {
277 Iterator iter = room.values().iterator();
278 while (iter.hasNext())
279 {
280 Member m = (Member)iter.next();
281 if (m.getName()==null)
282 continue;
283 buf.append("<li>");
284 buf.append(encodeText(m.getName()));
285 buf.append("</li>\n");
286 }
287 }
288 buf.append("</ul>\n");
289 response.elementResponse("members", buf.toString());
290 }
291
292
293 private static class Message
294 {
295 private String _from;
296 private String _text;
297 private boolean _alert;
298
299 Message(String from, String text, boolean alert)
300 {
301 _from=from;
302 _text=text;
303 _alert=alert;
304 }
305
306 boolean isAlert()
307 {
308 return _alert;
309 }
310
311 public String toString()
312 {
313 return "<chat from=\""+_from+"\" alert=\""+_alert+"\">"+encodeText(_text)+"</chat>";
314 }
315
316
317
318 }
319
320 private class Member
321 {
322 private HttpSession _session;
323 private String _name;
324 private List _messages = new ArrayList();
325 private Continuation _continuation;
326
327 Member(HttpSession session, String name)
328 {
329 _session=session;
330 _name=name;
331 }
332
333
334
335
336
337 public String getName()
338 {
339 return _name;
340 }
341
342
343
344
345
346 public void setName(String name)
347 {
348 _name = name;
349 }
350
351
352
353
354
355 public HttpSession getSession()
356 {
357 return _session;
358 }
359
360
361
362
363
364
365 public Continuation getContinuation()
366 {
367 return _continuation;
368 }
369
370
371
372
373
374 public void setContinuation(Continuation continuation)
375 {
376 if (continuation!=null && _continuation!=null && _continuation!=continuation)
377 _continuation.resume();
378 _continuation=continuation;
379 }
380
381
382 public void addMessage(Message event)
383 {
384 if (_name==null)
385 return;
386 _messages.add(event);
387 if (_continuation!=null)
388 _continuation.resume();
389 }
390
391
392 public boolean hasMessages()
393 {
394 return _messages!=null && _messages.size()>0;
395 }
396
397
398 public void rename(Map room,String name)
399 {
400 String oldName = getName();
401 setName(name);
402 if (oldName!=null)
403 ChatFilter.this.sendMessage(room,this,oldName+" has been renamed to "+name,true);
404 }
405
406
407 public boolean sendMessages(AjaxResponse response)
408 {
409 synchronized (this)
410 {
411 boolean alerts=false;
412 for (int i=0;i<_messages.size();i++)
413 {
414 Message event = (Message)_messages.get(i);
415 response.objectResponse("chat", event.toString());
416 alerts |= event.isAlert();
417 }
418 _messages.clear();
419 return alerts;
420 }
421 }
422
423 }
424 }