package com.collibra.server; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.SocketTimeoutException; import java.util.UUID; /** * Every time a new client connects to the server a new thread is created for the client's session. * The session stays active until the client times out or the client sends a disconnect message. * @version 1.0 * @author Yordan Kirov * @since 21/11/2018 */ class ClientSessionThread extends Thread { /** Socket used for communication between the server and the client. */ private final Socket clientSocket; /** The time when the client has connected. */ private long startTime; /** The name of the client that is retrieved after the initial communication. */ private String clientName = null; /** * Indicator whether the client session is still active or not. * When it is made inactive the client gets disconnected. */ private boolean isSessionActive; /** Universally unique identifier of the client session. */ private final String sessionId; /** * Constructor * Initializes the start time of the connection. * Sets the session to active. * Generates a universally unique identifier of the client session. * @param clientSocket the socket on which the client connects to the server. */ public ClientSessionThread(Socket clientSocket) { System.out.println("Client connected."); this.clientSocket = clientSocket; this.startTime = System.currentTimeMillis(); this.isSessionActive = true; this.sessionId = UUID.randomUUID().toString(); } /** * Initializes the communication between the server and the client. * Sends a first message to the client. * Sets the client name if the client sends it properly or waits to receive it. * Takes all commands of the client and answers to them. * When an error occurs the connection with the client is closed. */ public void run() { PrintWriter out = null; BufferedReader in = null; try { out = new PrintWriter(clientSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); SimpleProtocol.sendFirstMessage(out, sessionId); String inputLine; while (isSessionActive && (inputLine = in.readLine()) != null) { if (this.clientName == null) { this.clientName = SimpleProtocol.retrieveClientName(out, inputLine); } else { acceptMessage(inputLine, out); } } } catch (SocketTimeoutException se) { System.out.println(this.clientName + " TIMED OUT!!!"); } catch (Exception e) { e.printStackTrace(); } finally { SimpleProtocol.sendGoodbyeMessage(out, this.clientName, startTime); disconnect(); } } /** * Accepts client messages and executes the commands according to the SimpleProtocol. * @param clientMessage message coming from the client * @param out the PrintWriter with which the server sends messages to the client. */ private void acceptMessage(String clientMessage, PrintWriter out) { if ("BYE MATE!".equals(clientMessage)) { this.isSessionActive = false; return; } String serverMessage; if (clientMessage.startsWith("ADD NODE ")) { serverMessage = SimpleProtocol.addNode(clientMessage); } else if (clientMessage.startsWith("ADD EDGE ")) { serverMessage = SimpleProtocol.addEdge(clientMessage); } else if (clientMessage.startsWith("REMOVE NODE ")) { serverMessage = SimpleProtocol.removeNode(clientMessage); } else if (clientMessage.startsWith("REMOVE EDGE ")) { serverMessage = SimpleProtocol.removeEdge(clientMessage); } else if (clientMessage.startsWith("SHORTEST PATH ")) { serverMessage = SimpleProtocol.getShortestPath(clientMessage); } else if (clientMessage.startsWith("CLOSER THAN ")) { serverMessage = SimpleProtocol.getCloserThan(clientMessage); } else { serverMessage = SimpleProtocol.unsupportedCommand(); } debugToConsole(clientMessage, serverMessage); out.println(serverMessage); } private void debugToConsole(String clientMessage, String serverMessage) { if (Server.DEBUG) { System.out.println(">>>" + clientMessage); System.out.println(serverMessage); } } private void disconnect() { System.out.println("Closing the connection: " + this.clientName); try { if (clientSocket != null) { clientSocket.close(); } } catch (Exception e) { e.printStackTrace(); } } }