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 }