Package hamsam.protocol.msn

Source Code of hamsam.protocol.msn.ReaderThread

/*
* Hamsam - Instant Messaging API
* Copyright (C) 2003 Raghu K
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

package hamsam.protocol.msn;

import hamsam.net.Connection;
import hamsam.util.log.LogManager;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* This thread reads incoming commands from the server.
*/
class ReaderThread extends Thread
{
  /**
   * The MSN server associated with this reader thread.
   */
  private MsnServer server;

  /**
   * Connection to read the commands from.
   */
  private Connection conn;

  /**
   * Buffer to put the incoming commands.
   */
  private Vector buff;

  /**
   * Flag used to stop this thread.
   */
  private volatile boolean stop;

  /**
   * Constructs a reader thread that uses a specified connection.
   * <code>buff</code> is a buffer that has to be filled with
   * the commands received from the server.
   *
   * @param conn the connection to read the commands from.
   * @param buff the buffer to hold the commands received.
   */
  ReaderThread(MsnServer server, Connection conn, Vector buff)
  {
    this.server = server;
    this.conn = conn;
    this.buff = buff;
  }

  /**
   * Runs this thread.
   */
  public void run()
  {
    try
    {
      BufferedReader rd = new BufferedReader(
          new InputStreamReader(conn.getInputStream(), "UTF-8"));
      Logger logger = LogManager.getLogger();

      while(!stop)
      {
        AbstractCommand cmd = readNextCommand(rd);

        // If there is nothing to be read, wait for some time and then retry.
        if(cmd == null)
        {
          Thread.sleep(500);
          continue;
        }

        String msg = "Server: " + cmd.toString();
        if(!msg.endsWith("\n"))
          msg += '\n';
        logger.logp(Level.INFO, this.getClass().getName(), "run", msg);

        synchronized(buff)
        {
          buff.add(cmd);
          buff.notify();
        }
      }
    }
    catch(IOException e)
    {
      server.readerExited();
    }
    catch(InterruptedException e)
    {
      server.readerExited();     
    }
  }

  /**
   * Stop this thread.
   */
  void stopThread()
  {
    stop = true;
  }

  /**
   * Returns the next command from the connection, or null if nothing is available.
   *
   * @return next command from the connection, or null if nothing is available.
   */
  private AbstractCommand readNextCommand(BufferedReader rd) throws IOException
  {
    if(!rd.ready())
      return null;

    String line = rd.readLine();
    if(line == null)
      return null;

    StringTokenizer tok = new StringTokenizer(line);
    String type = tok.nextToken();
    if(type.equals("MSG"))
      return getNewMessage(tok, rd);
    else if(isErrorCode(type))
      return getNewErrorCommand(type, tok);
    else
    {
      Command cmd = new Command(type);
      if(hasTransactionID(type))
      {
        String token = tok.nextToken();
        try
        {
          cmd.setTransactionID(new Integer(token));
        }
        catch(NumberFormatException e)
        {
          cmd.addParam(token);
        }
      }
      while(tok.hasMoreTokens())
        cmd.addParam(tok.nextToken());
      return cmd;
    }
  }

  /**
   * Check if a string is an error code.
   *
   * @return true if this string represents an MSN error code, false otherwise.
   */
  private boolean isErrorCode(String str)
  {
    if(str == null)
      return false;
    else if(str.length() != 3)
      return false;
    else
    {
      try
      {
        Integer.parseInt(str);
        return true;
      }
      catch(NumberFormatException e)
      {
        return false;
      }
    }
  }

  /**
   * Read the body part of a message from the server stream, given its length.
   *
   * @param rd reader to read from.
   * @param count number of characters to be read
   * @return the body of the message
   * @exception IOException if an I/O error occurs.
   */
  private char[] readMessageBody(BufferedReader rd, int count) throws IOException
  {
    char[] ret = new char[count];
    rd.read(ret, 0, count);
    return ret;
  }

  /**
   * Get a new message from the connection.
   *
   * @param tok StringTokenizer to get passport, alias, and message length.
   * @param rd Used to read the message body.
   */
  private MsnMessage getNewMessage(StringTokenizer tok, BufferedReader rd) throws IOException
  {
    String passport = tok.nextToken();
    String alias = tok.nextToken();
    int count = Integer.parseInt(tok.nextToken());

    char[] data = readMessageBody(rd, count);
    MsnMessage msg = new MsnMessage(passport, alias, data);
    return msg;
  }

  /**
   * Returns an error command as specified by parameters.
   *
   * @param type the type of the error command.
   * @param tok StringTokenizer to get transaction id, if any.
   */
  private ErrorCommand getNewErrorCommand(String type, StringTokenizer tok)
  {
    ErrorCommand err = new ErrorCommand(type);
    if(tok.hasMoreTokens())
    {
      try
      {
        err.setTransactionID(new Integer(tok.nextToken()));
      }
      catch(NumberFormatException e)
      {
        // This is a server generated error - no transaction ID available
      }
    }
    return err;
  }

  /**
   * Checks whether this command can have a transaction ID.
   *
   * @param type the type identifier of command to check.
   * @return true, if this command will have transaction id, false otherwise.
   */
  private boolean hasTransactionID(String type)
  {
    return (!type.equals("MSG") && !type.equals("NLN") &&
          !type.equals("FLN") && !type.equals("RNG") &&
          !type.equals("JOI") && !type.equals("BYE") &&
          !type.equals("OUT") && !type.equals("BPR") &&
          !type.equals("CHL") && !type.equals("GTC") &&
          !type.equals("LSG") && !type.equals("LST") &&
          !type.equals("BPR") && !type.equals("QNG"));
  }
}
TOP

Related Classes of hamsam.protocol.msn.ReaderThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.