Package pong.server.model

Source Code of pong.server.model.ServerProtocolThread

package pong.server.model;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.LinkedList;
import java.util.Queue;

import pong.common.Debugger;
import pong.common.Message;
import pong.common.PlayerMovementInformation;
import pong.common.Position;
import pong.server.ServerSettings;

/**
* This class manages the communication among the server and a client.
*
* @author Lorenzo Gatto
*
*/
public class ServerProtocolThread extends Thread {

  private final Socket socket;
  private final Player player;
  private final ServerModel server;
  private ObjectOutputStream output;
  private ObjectInputStream input;
  private final Integer playerIndex;
  private boolean roundRunning;
  private final Queue<Message> messagesQueue;

  /**
   * Initializes the ServerPRotocolThread and set the player to be connected.
   *
   * @param socket
   *            the socket to which the player connected
   * @param player
   *            the player that connected to that socket
   * @param server
   *            a pointer to the server model
   * @param playerIndex
   *            the player index
   */
  public ServerProtocolThread(final Socket socket, final Player player, final ServerModel server,
      final int playerIndex) {
    super();
    this.socket = socket;
    this.player = player;
    this.server = server;
    this.player.setConnected(true);
    this.playerIndex = playerIndex;
    this.messagesQueue = new LinkedList<>();
  }

  /**
   * Create the connection, send player index and send messages periodically.
   */
  @Override
  public synchronized void run() {
    try {
      try {
        this.socket.setTcpNoDelay(true);
        OutputStream o;
        InputStream i;
        o = socket.getOutputStream();
        i = socket.getInputStream();
        this.output = new ObjectOutputStream(o);
        this.input = new ObjectInputStream(i);
      } catch (IOException e) {
        onDisconnect();
        return;
      }
      sendPlayerIndex();
      while (true) {
        // Pause to allow other thread to access synchonized method and not to saturate the
        // connection
        this.wait(ServerSettings.SERVER_SLEEP_TIME);
        if (!this.roundRunning) {
          // Debugger.printLine("Checking if player " +
          // this.playerIndex + " is alive");
          checkAlive();
        }
        sendMessagesOnQueue();
        if (this.roundRunning) {
          sendPositionInformation();
          getMovementInformation();
        }
      }
    } catch (InterruptedException e) {
      return;
    }
  }

  /**
   * This method tell the client the other player disconnected asynchronously.
   */
  public synchronized void otherDisconnectedWhilePlayingEvent() {
    final Message m = new Message(Message.Type.OTHER_DISCONNECTED, null);
    this.messagesQueue.add(m);
  }

  /**
   * This method tell the client the match begins asynchronously.
   *
   * @param roundNumber
   *            the number of rounds for the match
   */
  public synchronized void matchBeginsEvent(final int roundNumber) {
    Debugger.printLine("ServerProtocolThread.matchBeginsEvent called for player "
        + this.playerIndex);
    final Message m = new Message(Message.Type.MATCH_BEGINS, Integer.valueOf(roundNumber));
    this.messagesQueue.add(m);
  }

  /**
   * This method tell the client that the round ended and tells him if he won it.
   *
   * @param won
   *            true or false
   */
  public synchronized void roundEndEvent(final Boolean won) {
    final Message m = new Message(Message.Type.ROUND_END, won);
    this.messagesQueue.add(m);
  }

  /**
   * This method tell the client the round begins asynchronously.
   */
  public synchronized void roundBeginsEvent() {
    Debugger.printLine("ServerProtocolThread.roundBeginsEvent called for player "
        + this.playerIndex);
    final Message m = new Message(Message.Type.ROUND_BEGINS, null);
    this.messagesQueue.add(m);
  }

  /**
   * This method interrupts the thread.
   */
  @Override
  public synchronized void interrupt() {
    Debugger.printLine("ServerProtocolThread.interrupt");
    super.interrupt();
    try {
      this.input.close();
      this.output.close();
      this.socket.close();
    } catch (IOException e) {
      // DO NOTHING
    }
  }

  /**
   * Tells the player that the match ended.
   */
  public synchronized void matchEndsEvent() {
    // CURRENT PROTOCOL IMPLEMENTATION DOES NOT NEED TO SEND A MESSAGE FOR
    // THIS EVENT
  }

  /**
   * This method sends messages that were to be sent asynchronously
   */
  private void sendMessagesOnQueue() {
    while (this.messagesQueue.size() != 0) {
      final Message m = this.messagesQueue.remove();
      sendMessage(m);
      if (m.getMessageType() == Message.Type.OTHER_DISCONNECTED
          || m.getMessageType() == Message.Type.ROUND_END
          || m.getMessageType() == Message.Type.MATCH_BEGINS) {
        this.roundRunning = false;
      } else if (m.getMessageType() == Message.Type.ROUND_BEGINS) {
        this.roundRunning = true;
      }
    }
  }

  /**
   * This method sends the player index to the client.
   */
  private void sendPlayerIndex() {
    Debugger.printLine("ServerProtocolThread.sendPlayerIndex called for player "
        + this.playerIndex);
    final Message m = new Message(Message.Type.YOUR_PLAYER_INDEX, playerIndex);
    sendMessage(m);
  }

  /**
   * This method sends where objects are to the client
   */
  private void sendPositionInformation() {
    final Position[] pos = server.getObjectsPositions();
    // Debugger.printLine("ServerProtocolThread.sendPositions called");
    // Debugger.printLine("Player 1 position " + pos[1].getY());
    final Message m = new Message(Message.Type.POSITIONS, pos);
    sendMessage(m);
  }

  /**
   * This method gets how the player is moving from the client and updates the MovementInformation
   * object inside the Player instance.
   */
  private void getMovementInformation() {
    if (this.isInterrupted()) {
      return;
    }
    Debugger.printLine("ServerProtocolThread.getMovementInformation called for player"
        + this.playerIndex + " time " + System.currentTimeMillis());
    Message message = null;
    try {
      message = (Message) this.input.readObject();
    } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      System.exit(1);
    } catch (IOException e) {
      onDisconnect();
      return;
    }
    assert (message != null);
    assert (message.getMessageType() == Message.Type.MOVEMENT);
    this.player.setMovementInformation((PlayerMovementInformation) message.getContent());
    Debugger.printLine("Movement information received for player" + this.playerIndex + " time "
        + System.currentTimeMillis());
  }

  /**
   * Sends a message to the client checking for failure.
   *
   * @param message
   *            the message to be sent to the client
   */
  private void sendMessage(final Message message) {
    if (this.isInterrupted()) {
      return;
    }
    Debugger.printLine("ServerProtocolThread.sendMessage called for player " + this.playerIndex
        + " " + message.getMessageType().name() + " time " + System.currentTimeMillis());
    try {
      this.output.writeObject(message);
      this.output.flush();
      this.output.reset();
    } catch (IOException e) {
      onDisconnect();
    }
  }

  /**
   * Player disconnects. This method tell the server and interrupt the thread.
   *
   */
  private void onDisconnect() {
    Debugger.printLine("ServerProtocolThread.onDisconnect called");
    this.player.setConnected(false);
    if (!this.isInterrupted()) {
      this.server.playerDisconnectedEvent(this);
      interrupt();
    }
  }

  /**
   * Sends a message just to make an IOException be thrown in case the player disconnects
   * unexpectedly or the connection fails.
   */
  private void checkAlive() {
    final Message m = new Message(Message.Type.ARE_YOU_ALIVE, null);
    sendMessage(m);
  }

}
TOP

Related Classes of pong.server.model.ServerProtocolThread

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.