Clover coverage report -
Coverage timestamp: Sun Oct 12 2003 22:57:21 PDT
file stats: LOC: 305   Methods: 11
NCLOC: 117   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
ClientHandler.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
 
 3   
 VRMoo Server - Virtual Reality Object Oriented MUD Server
 4   
 Copyright (C) 2001 - 2003  VRMoo Development Team
 5   
 
 6   
 
 7   
 This program is free software; you can redistribute it and/or modify
 8   
 it under the terms of the GNU General Public License as published by
 9   
 the Free Software Foundation; either version 2 of the License, or
 10   
 (at your option) any later version.
 11   
 
 12   
 This program is distributed in the hope that it will be useful,
 13   
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 14   
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15   
 GNU General Public License for more details.
 16   
 
 17   
 You should have received a copy of the GNU General Public License
 18   
 along with this program; if not, write to the Free Software
 19   
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 20   
 
 21   
 
 22   
 For information about VRMoo and its authors, please visit the website:
 23   
 http://www.vrmoo.org/
 24   
 
 25   
 */
 26   
 
 27   
 package org.vrmoo.server.client;
 28   
 
 29   
 import java.io.IOException;
 30   
 import java.io.InputStream;
 31   
 import java.io.OutputStream;
 32   
 import java.net.Socket;
 33   
 
 34   
 import org.vrmoo.common.exception.VRMooException;
 35   
 import org.vrmoo.common.exception.VRMooParseException;
 36   
 import org.vrmoo.common.util.CommandHandler;
 37   
 import org.vrmoo.common.util.CommandProcessor;
 38   
 import org.vrmoo.common.util.ParserUtility;
 39   
 
 40   
 import org.vrmoo.server.command.GetNextIDCommand;
 41   
 import org.vrmoo.server.data.WorldManager;
 42   
 import org.vrmoo.server.world.World;
 43   
 
 44   
 /**
 45   
  * This class is responsible for dealing with a client once it has connected.
 46   
  * It assigns a <code>ClientReader</code> and a <code>ClientWriter</code> to
 47   
  * the client socket created by the server. If this class detects that the
 48   
  * client has disconnected, it will clean up all the client related objects and
 49   
  * stop all client related threads.
 50   
  *
 51   
  * @author Jeff Weston
 52   
  */
 53   
 public class ClientHandler extends CommandHandler
 54   
 {
 55   
     /**
 56   
      * The <code>ClientReader</code> for this client.
 57   
      */
 58   
     private ClientReader clientReader;
 59   
 
 60   
     /**
 61   
      * The <code>ClientWriter</code> for this client.
 62   
      */
 63   
     private ClientWriter clientWriter;
 64   
 
 65   
     /**
 66   
      * The unique identifier for this client.
 67   
      */
 68   
     private int id;
 69   
 
 70   
     /**
 71   
      * The world that this client is currently connected to.
 72   
      */
 73   
     private World world;
 74   
 
 75   
     /**
 76   
      * This constructor takes a <code>Socket</code> that just connected to the
 77   
      * server and sets up this <code>ClientHandler</code> object to handle it.
 78   
      * Assigns a <code>ClientWriter</code> to write to the socket and a
 79   
      * <code>ClientReader</code> to read from it.
 80   
      *
 81   
      * @param clientSocket   the client socket generated by the server
 82   
      *
 83   
      * @throws IOException   for any IO problems that occur
 84   
      */
 85  0
     public ClientHandler( Socket clientSocket ) throws IOException
 86   
     {
 87  0
         addCommandProcessor( new ProtocolCommandProcessor( ) );
 88  0
         addCommandProcessor( new WorldConnectCommandProcessor( this ) );
 89  0
         addCommandProcessor( GetNextIDCommand.getInstance( ) );
 90   
 
 91  0
         OutputStream outputStream = clientSocket.getOutputStream( );
 92  0
         InputStream  inputStream  = clientSocket.getInputStream( );
 93   
 
 94  0
         id = AllClients.getNextID( );
 95  0
         System.out.println( "Client Connected: " + id );
 96   
 
 97  0
         clientWriter = new ClientWriter( outputStream, this );
 98  0
         clientReader = new ClientReader( inputStream, this );
 99   
 
 100   
         // Send out the protocol versions that the server supports.
 101  0
         writeLine( "protocol: 1" );
 102   
 
 103   
         // Register to receive broadcast messages.
 104  0
         AllClients.register( this );
 105   
     }
 106   
 
 107   
     /**
 108   
      * Get the unique identifier of this client.
 109   
      *
 110   
      * @return the unique indentifier of this client
 111   
      */
 112  0
     public int getClientID( )
 113   
     {
 114  0
         return id;
 115   
     }
 116   
 
 117   
     /**
 118   
      * This method is called if the <code>ClientReader</code> or the
 119   
      * <code>ClientWriter</code> detect that the client has been disconnected.
 120   
      */
 121  0
     public synchronized void clientDisconnected( )
 122   
     {
 123  0
         System.out.println( "Client Disconnected: " + id );
 124   
 
 125  0
         clientWriter.stop( );
 126  0
         clientReader.stop( );
 127   
 
 128  0
         AllClients.unregister( this );
 129  0
         if ( world != null )
 130   
         {
 131  0
             world.disconnectClient( this );
 132   
         }
 133   
     }
 134   
 
 135   
     /**
 136   
      * This method is called when you want to write a line of text out to
 137   
      * this client.
 138   
      *
 139   
      * @param line   the line of text to write out
 140   
      */
 141  0
     public synchronized void writeLine( String line )
 142   
     {
 143  0
         write( line );
 144  0
         clientWriter.writeData( '\n' );
 145  0
         clientWriter.writeData( '\r' );
 146   
     }
 147   
 
 148   
     /**
 149   
      * This method is called when you want to write some text without a
 150   
      * carriage return out to this client.
 151   
      *
 152   
      * @param text   the text to write out
 153   
      */
 154  0
     public synchronized void write( String text )
 155   
     {
 156  0
         for ( int i = 0; i < text.length( ); i++ )
 157   
         {
 158  0
             clientWriter.writeData( text.charAt( i ) );
 159   
         }
 160   
     }
 161   
 
 162   
     /**
 163   
      * Takes a command typed in by the client connected to the socket and
 164   
      * processes it.
 165   
      *
 166   
      * @param command   the command to process
 167   
      *
 168   
      * @throws VRMooException for any errors while processing the command
 169   
      */
 170  0
     public synchronized void processCommand( String command )
 171   
             throws VRMooException
 172   
     {
 173  0
         handleCommand( command, id + "" );
 174   
     }
 175   
 
 176   
     /**
 177   
      * Private inner class implementing the <code>CommandProcessor</code>
 178   
      * interface for dealing with the "protocol" command sent from the server.
 179   
      */
 180   
     private class ProtocolCommandProcessor implements CommandProcessor
 181   
     {
 182   
         /**
 183   
          * The prefix for the command handled by this processor.
 184   
          */
 185   
         private static final String PREFIX = "protocol:";
 186   
 
 187   
         /**
 188   
          * Returns the command prefix used to recognize commands that this
 189   
          * processor can handle.
 190   
          *
 191   
          * @return the command prefix
 192   
          */
 193  0
         public String getCommandPrefix( )
 194   
         {
 195  0
             return PREFIX;
 196   
         }
 197   
 
 198   
         /**
 199   
          * Process a command matching the command prefix established by the
 200   
          * <code>getCommandPrefix()</code> method.
 201   
          * <p>
 202   
          * The 'protocol' command tells the server which version of the VRMoo
 203   
          * protocol that the client wishes to use. If the server does not
 204   
          * support the version of the protcol that the client requests, the
 205   
          * server disconnects the client.
 206   
          *
 207   
          * @param command     the command to process
 208   
          * @param extraData   extra data that isn't part of the command but may
 209   
          *                      be needed for dealing with the command (such as
 210   
          *                      the ID of the client that sent the command)
 211   
          *
 212   
          * @throws VRMooParseException   for any parsing errors while processing
 213   
          *                                 the command
 214   
          */
 215  0
         public void processCommand( String command, String extraData )
 216   
                 throws VRMooParseException
 217   
         {
 218  0
             int version = ParserUtility.parseInt(
 219   
                     command.substring( PREFIX.length( ) ).trim( ) );
 220   
 
 221  0
             if ( version != 1 )
 222   
             {
 223  0
                 System.out.println( "Cannot negotiate protocol with client." );
 224  0
                 System.out.println( "Client requested: " + version );
 225  0
                 System.out.println( "We support: 1" );
 226  0
                 clientDisconnected( );
 227   
             }
 228   
             else
 229   
             {
 230   
                 // Send out the ID of the client so that
 231   
                 // it won't respond to its own events.
 232  0
                 writeLine( "id: " + id );
 233   
             }
 234   
         }
 235   
     }
 236   
 
 237   
     /**
 238   
      * Private inner class implementing the <code>CommandProcessor</code>
 239   
      * interface for dealing with the "worldConnect" command sent from the
 240   
      * client.
 241   
      */
 242   
     private class WorldConnectCommandProcessor implements CommandProcessor
 243   
     {
 244   
         /**
 245   
          * The prefix for the command handled by this processor.
 246   
          */
 247   
         private static final String PREFIX = "worldConnect:";
 248   
 
 249   
         /**
 250   
          * A reference to the clientHandler that constructed this processor.
 251   
          * Allows us to specify which client is processing the command.
 252   
          */
 253   
         private ClientHandler clientHandler;
 254   
 
 255   
         /**
 256   
          * Construct this processor from the specified client.
 257   
          *
 258   
          * @param clientHandler   the <code>ClientHandler</code> constructing
 259   
          *                          this class
 260   
          */
 261  0
         public WorldConnectCommandProcessor( ClientHandler clientHandler )
 262   
         {
 263  0
             this.clientHandler = clientHandler;
 264   
         }
 265   
 
 266   
         /**
 267   
          * Returns the command prefix used to recognize commands that this
 268   
          * processor can handle.
 269   
          *
 270   
          * @return the command prefix
 271   
          */
 272  0
         public String getCommandPrefix( )
 273   
         {
 274  0
             return PREFIX;
 275   
         }
 276   
 
 277   
         /**
 278   
          * Process a command matching the command prefix established by the
 279   
          * <code>getCommandPrefix()</code> method.
 280   
          *
 281   
          * @param command     the command to process
 282   
          * @param extraData   extra data that isn't part of the command but may
 283   
          *                      be needed for dealing with the command (such as
 284   
          *                      the ID of the client that sent the command)
 285   
          *
 286   
          * @throws VRMooParseException   for any parsing errors while processing
 287   
          *                                 the command
 288   
          */
 289  0
         public void processCommand( String command, String extraData )
 290   
                 throws VRMooParseException
 291   
         {
 292  0
             if ( world != null )
 293   
             {
 294  0
                 world.disconnectClient( clientHandler );
 295   
             }
 296   
 
 297  0
             String worldName =
 298   
                     command.substring( PREFIX.length( ) ).trim( );
 299   
 
 300  0
             world = WorldManager.getWorld( worldName );
 301  0
             world.connectClient( clientHandler );
 302   
         }
 303   
     }
 304   
 }
 305