View Javadoc

1   //========================================================================
2   //$Id: ChatFilter.java,v 1.4 2005/11/14 11:00:33 gregwilkins Exp $
3   //Copyright 2004-2005 Mort Bay Consulting Pty. Ltd.
4   //------------------------------------------------------------------------
5   //Licensed under the Apache License, Version 2.0 (the "License");
6   //you may not use this file except in compliance with the License.
7   //You may obtain a copy of the License at 
8   //http://www.apache.org/licenses/LICENSE-2.0
9   //Unless required by applicable law or agreed to in writing, software
10  //distributed under the License is distributed on an "AS IS" BASIS,
11  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  //See the License for the specific language governing permissions and
13  //limitations under the License.
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   * @author gregw
39   * @deprecated Use Cometd
40   */
41  public class ChatFilter extends AjaxFilter
42  {       
43      private Map chatrooms;
44      
45  
46      /* ------------------------------------------------------------ */
47      /* 
48       * @see org.mortbay.ajax.AjaxFilter#init(javax.servlet.FilterConfig)
49       */
50      public void init(FilterConfig filterConfig) throws ServletException
51      {
52          super.init(filterConfig);
53          chatrooms=new HashMap();
54      }
55      
56      /* ------------------------------------------------------------ */
57      /* 
58       * @see org.mortbay.ajax.AjaxFilter#destroy()
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       * @see org.mortbay.ajax.AjaxFilter#handle(java.lang.String, javax.servlet.http.HttpServletRequest, org.mortbay.ajax.AjaxFilter.AjaxResponse)
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             // exists already, so just update name
130             sendMessage(room,member,"has joined the chat",true);
131             
132             //response.objectResponse("joined", "<joined from=\""+name+"\"/>");
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         //response.objectResponse("left", "<left from=\""+member.getName()+"\"/>");
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                     // duplicate frames!
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          * @return Returns the name.
336          */
337         public String getName()
338         {
339             return _name;
340         }
341 
342         /* ------------------------------------------------------------ */
343         /**
344          * @param name The name to set.
345          */
346         public void setName(String name)
347         {
348             _name = name;
349         }
350 
351         /* ------------------------------------------------------------ */
352         /**
353          * @return Returns the session.
354          */
355         public HttpSession getSession()
356         {
357             return _session;
358         }
359 
360 
361         /* ------------------------------------------------------------ */
362         /**
363          * @param continuation The continuation to set.
364          */
365         public Continuation getContinuation()
366         {
367             return _continuation;
368         }
369         
370         /* ------------------------------------------------------------ */
371         /**
372          * @param continuation The continuation to set.
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 }