KOProject/SimpleProtocol.java

257 lines
9.5 KiB
Java
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.collibra.server;
import java.io.PrintWriter;
/**
* A simple protocol for exchanging messages between a server and clients.
*
* @version 1.0
* @author Yordan Kirov
* @since 21/11/2018
*
*/
class SimpleProtocol {
/**
* Sends a first message to every client that connects to the server.
* @param out the PrintWriter with which the server sends messages to the client.
* @param sessionId identification of the session with the current client.
*/
public static void sendFirstMessage(PrintWriter out, String sessionId) {
out.println("HI, I'M " + sessionId);
}
/**
* Extracts and validates the name of the connected client from its first message.
*
* The server expects a message starting with "HI, I'M " and followed by the name of the client.
* If the client doesn't fulfil the server expectations, by sending the wrong command or sending
* a clientName that is non alphanumeric plus the character "-", the server is awaiting for the client to give a
* proper name and doesn't accept other commands before that.
*
* @param out the PrintWriter with which the sever sends messages to the client.
* @param message received from a client.
*
* @return clientName - the name of the client if it is valid, otherwise returns null;
*/
public static String retrieveClientName(PrintWriter out, String message) {
String clientName;
if (message.contains("HI, I'M ")) {
String unvalidatedClientName = message.replace("HI, I'M ", "");
if (isValidName(unvalidatedClientName)) {
clientName = unvalidatedClientName;
System.out.println("Connected client: " + clientName);
out.println("HI " + clientName);
return clientName;
}
}
out.println(unsupportedCommand());
return null;
}
/**
* Sends a message to the client before disconnecting.
* The message includes the name of the client and the duration of the connection.
*
* @param out the PrintWriter with which the sever sends messages to the client.
* @param clientName the name of the connected client.
* @param startTime the time in milliseconds when the client connected.
*/
public static void sendGoodbyeMessage(PrintWriter out, String clientName, long startTime) {
if (out != null) {
System.out.println("GOODBYE MESSAGE!" + clientName);
long stopTime = System.currentTimeMillis();
long duration = stopTime - startTime;
out.println("BYE " + clientName + ", WE SPOKE FOR " + duration + " MS");
}
}
/**
* Adds a node (as a string) to the GRAPH.
* When the name of the node is only including alphanumeric character,
* plus the character "-" and the node doesn't already exist.
*
* @param message received from a client.
* @return returns an error message if the node already exists
* or success message if the node has been successfully added.
*/
public static String addNode(String message) {
String nodeName = message.replace("ADD NODE ", "");
if (!isValidName(nodeName)) {
return unsupportedCommand();
}
if (!Server.GRAPH.containsNode(nodeName)) {
Server.GRAPH.addNode(nodeName);
return "NODE ADDED";
} else {
return "ERROR: NODE ALREADY EXISTS";
}
}
/**
* Adds a directed edge to the GRAPH.
* A directed edge has three parts, node from which it points, node to which it points
* and weight which is a positive integer.
* When the names of the nodes between the edge is are already existing and
* the format of the command is valid and the weight is a positive integer.
*
* @param message received from a client.
* @return returns an error message if the the edge can't be added
* or success message if the edge has been successfully added.
*/
public static String addEdge(String message) {
String edgeString = message.replace("ADD EDGE ", "");
String[] edgeParts = edgeString.split(" ");
if (!isValidEdge(edgeParts)) {
return unsupportedCommand();
}
String fromName = edgeParts[0];
String toName = edgeParts[1];
if (Server.GRAPH.containsNode(fromName) && Server.GRAPH.containsNode(toName)) {
int weight = Integer.valueOf(edgeParts[2]);
Server.GRAPH.addEdge(fromName, toName, weight);
return "EDGE ADDED";
}
return "ERROR: NODE NOT FOUND";
}
/**
* Removes a node from the GRAPH, only when the node is already existing.
* All edges that are linked to the removed node will also be removed.
* @param message received from a client.
* @return returns an error message if the node doesn't exist
* or success message if the node has been successfully removed.
*/
public static String removeNode(String message) {
String nodeName = message.replace("REMOVE NODE ", "");
if (Server.GRAPH.containsNode(nodeName)) {
Server.GRAPH.removeNode(nodeName);
return "NODE REMOVED";
} else {
return "ERROR: NODE NOT FOUND";
}
}
/**
* Removes all directed edges from the GRAPH when the command is valid
* and the both nodes that form the graph are existing.
* @param message received from a client.
* @return returns an error message if the command is invalid or the nodes between the graph aren't existing.
* Returns a success message if the edges have been successfully removed.
*/
public static String removeEdge(String message) {
String edgeString = message.replace("REMOVE EDGE ", "");
String[] edgeParts = edgeString.split(" ");
if (edgeParts.length != 2) {
return unsupportedCommand();
}
String fromName = edgeParts[0];
String toName = edgeParts[1];
if (Server.GRAPH.containsNode(fromName) && Server.GRAPH.containsNode(toName)) {
Server.GRAPH.removeEdge(fromName, toName);
return "EDGE REMOVED";
}
return "ERROR: NODE NOT FOUND";
}
/**
* Calculates the sum of the weights of the shortest path between two nodes in the GRAPH,
* when the input of the command is valid and the nodes exist in the GRAPH.
* @param message received from a client.
* @return the sum of the weights of the shortest path between two nodes.
* Returns an error message if the command is invalid or the nodes of the GRAPH aren't existing.
*/
public static String getShortestPath(String message) {
String fromAndTo = message.replace("SHORTEST PATH ", "");
String[] fromTo = fromAndTo.split(" ");
if (fromTo.length != 2) {
return unsupportedCommand();
}
String from = fromTo[0];
String to = fromTo[1];
if (Server.GRAPH.containsNode(from) && Server.GRAPH.containsNode(to)) {
return String.valueOf(Server.GRAPH.getShortestPathDistance(from, to));
}
return "ERROR: NODE NOT FOUND";
}
/**
* Finds all the nodes that are closer to a node from the client message than the given weight.
*
* For example:
* Simple graph: Mark -­ 5 -­> Michael -­ 2 -­> Madeleine -­ 8 -­> Mufasa
* CLOSER THAN 8 Mark
* Would return: Madeleine,Michael
* Because Michael is at weight 5 from Mark and Madeleine is at weight 7 (5+2) from Mark.
*
* @param message received from a client.
* @return a comma separated list(no spaces) of found nodes, that are closer to a node from the client message,
* sorted alphabetically by name, not including the starting node.
* Returns an error message if the command is invalid or the node of the GRAPH isn't existing.
*/
public static String getCloserThan(String message) {
String weightAndNode = message.replace("CLOSER THAN ", "");
String[] weightNode = weightAndNode.split(" ");
if (weightNode.length != 2 || !isValidWeightString(weightNode[0])) {
return unsupportedCommand();
}
int weight = Integer.valueOf(weightNode[0]);
String nodeName = weightNode[1];
if (Server.GRAPH.containsNode(nodeName)) {
String path = Server.GRAPH.getNodesCloserThan(weight, nodeName);
return path;
}
return "ERROR: NODE NOT FOUND";
}
/**
* Returns string for unsupported command.
* @return string for unsupported command.
*/
public static String unsupportedCommand() {
return "SORRY, I DIDN'T UNDERSTAND THAT";
}
private static boolean isValidEdge(String[] input) {
if (input.length != 3) {
return false;
}
String weightString = input[2];
boolean isValidWeightString = isValidWeightString(weightString);
return isValidWeightString;
}
private static boolean isValidWeightString(String weightString) {
return weightString.length() > 0 &&
weightString.chars().allMatch(Character::isDigit);
}
private static boolean isValidName(String input) {
return input.matches("[A-Za-z0-9-]+");
}
}