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