From fe8a158525c570e6a910210de717249442724245 Mon Sep 17 00:00:00 2001 From: Edward Knight Date: Sun, 29 Nov 2015 15:57:52 +0000 Subject: [PATCH] Updated CheckStyle, corrected indentation --- build.gradle | 5 +- haver_checks.xml | 16 +- src/main/java/chat/haver/server/Client.java | 116 ++--- src/main/java/chat/haver/server/Message.java | 160 +++---- src/main/java/chat/haver/server/Queue.java | 144 +++---- src/main/java/chat/haver/server/Room.java | 398 +++++++++--------- src/main/java/chat/haver/server/Router.java | 292 ++++++------- .../java/chat/haver/server/package-info.java | 5 + 8 files changed, 570 insertions(+), 566 deletions(-) create mode 100644 src/main/java/chat/haver/server/package-info.java diff --git a/build.gradle b/build.gradle index e6aeb34..e255d4b 100644 --- a/build.gradle +++ b/build.gradle @@ -4,8 +4,9 @@ version '0.1-SNAPSHOT' apply plugin: 'java' //javadoc.enabled = false apply plugin: 'application' -// apply plugin: 'checkstyle' // TODO: uncomment when finished JDoc comments -/*checkstyle { +/**apply plugin: 'checkstyle' // TODO: uncomment when finished JDoc comments +checkstyle { + toolVersion = '6.12.1' configFile = rootProject.file('haver_checks.xml') }*/ mainClassName = 'chat.haver.server.Main' diff --git a/haver_checks.xml b/haver_checks.xml index 3f90e7c..f5b6a7b 100644 --- a/haver_checks.xml +++ b/haver_checks.xml @@ -40,9 +40,8 @@ --> - - - + + @@ -120,10 +119,9 @@ - - - - + + + @@ -167,13 +165,13 @@ - - + + diff --git a/src/main/java/chat/haver/server/Client.java b/src/main/java/chat/haver/server/Client.java index 7914913..6fc2018 100644 --- a/src/main/java/chat/haver/server/Client.java +++ b/src/main/java/chat/haver/server/Client.java @@ -4,78 +4,78 @@ import java.util.List; public class Client { - // Change to read in from file instead of set in code later. - public static final String[] NAMES = { - "Blue Battleship", "Blue Boot", "Blue Dog", "Blue Iron", "Blue Racecar", "Blue Thimble", "Blue Tophat", "Blue Wheelbarrow", - "Green Battleship", "Green Boot", "Green Dog", "Green Iron", "Green Racecar", "Green Thimble", "Green Tophat", "Green Wheelbarrow", - "Orange Battleship", "Orange Boot", "Orange Dog", "Orange Iron", "Orange Racecar", "Orange Thimble", "Orange Tophat", "Orange Wheelbarrow", - "Purple Battleship", "Purple Boot", "Purple Dog", "Purple Iron", "Purple Racecar", "Purple Thimble", "Purple Tophat", "Purple Wheelbarrow", - "Red Battleship", "Red Boot", "Red Dog", "Red Iron", "Red Racecar", "Red Thimble", "Red Tophat", "Red Wheelbarrow", - "Yellow Battleship", "Yellow Boot", "Yellow Dog", "Yellow Iron", "Yellow Racecar", "Yellow Thimble", "Yellow Tophat", "Yellow Wheelbarrow"}; + // Change to read in from file instead of set in code later. + public static final String[] NAMES = { + "Blue Battleship", "Blue Boot", "Blue Dog", "Blue Iron", "Blue Racecar", "Blue Thimble", "Blue Tophat", "Blue Wheelbarrow", + "Green Battleship", "Green Boot", "Green Dog", "Green Iron", "Green Racecar", "Green Thimble", "Green Tophat", "Green Wheelbarrow", + "Orange Battleship", "Orange Boot", "Orange Dog", "Orange Iron", "Orange Racecar", "Orange Thimble", "Orange Tophat", "Orange Wheelbarrow", + "Purple Battleship", "Purple Boot", "Purple Dog", "Purple Iron", "Purple Racecar", "Purple Thimble", "Purple Tophat", "Purple Wheelbarrow", + "Red Battleship", "Red Boot", "Red Dog", "Red Iron", "Red Racecar", "Red Thimble", "Red Tophat", "Red Wheelbarrow", + "Yellow Battleship", "Yellow Boot", "Yellow Dog", "Yellow Iron", "Yellow Racecar", "Yellow Thimble", "Yellow Tophat", "Yellow Wheelbarrow"}; - private String name; - private Location location; - private final Object token; - private final Queue queue; - private static final int MESSAGES = 10; - private static final int MILLISECONDS = 5000; + private String name; + private Location location; + private final Object token; + private final Queue queue; + private static final int MESSAGES = 10; + private static final int MILLISECONDS = 5000; - public Client() { - this.token = generateToken(); + public Client() { + this.token = generateToken(); this.queue = new Queue(MESSAGES, MILLISECONDS); - } + } - //TODO Generate tokens - private Object generateToken() { - return null; - } + //TODO Generate tokens + private Object generateToken() { + return null; + } - //TODO Token validation - public boolean isValid() { - return true; - } + //TODO Token validation + public boolean isValid() { + return true; + } public boolean addToQueue() { return queue.add(); } - public Location getLocation() { - return location; - } + public Location getLocation() { + return location; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public Object getToken() {return token;} + public Object getToken() {return token;} - public void setName(final String name) { - if (Main.DEBUG && !(validName(name))) {System.err.println("Client:setName() : Invalid name");} // TODO: null check and fix error message - this.name = name; - } + public void setName(final String name) { + if (Main.DEBUG && !(validName(name))) {System.err.println("Client:setName() : Invalid name");} // TODO: null check and fix error message + this.name = name; + } - public void setLocation(final Location location) {this.location = location;} + public void setLocation(final Location location) {this.location = location;} - /** - * Tests if the specified name is valid. - * - * @param name The name to validate. - * @return True if the name is recognised. - */ - public static boolean validName(final String name) { - return Arrays.binarySearch(NAMES, name) >= 0; - } + /** + * Tests if the specified name is valid. + * + * @param name The name to validate. + * @return True if the name is recognised. + */ + public static boolean validName(final String name) { + return Arrays.binarySearch(NAMES, name) >= 0; + } - /** - * Tests if the specified names are valid. - * - * @param names The names to validate. - * @return True if all names are recognised. - */ - public static boolean validNames(final List names) { - for(String name : names) { - if (!validName(name)) return false; - } - return true; - } + /** + * Tests if the specified names are valid. + * + * @param names The names to validate. + * @return True if all names are recognised. + */ + public static boolean validNames(final List names) { + for(String name : names) { + if (!validName(name)) return false; + } + return true; + } } diff --git a/src/main/java/chat/haver/server/Message.java b/src/main/java/chat/haver/server/Message.java index b6189b5..1b39fcd 100644 --- a/src/main/java/chat/haver/server/Message.java +++ b/src/main/java/chat/haver/server/Message.java @@ -7,57 +7,57 @@ /** * All Messages have a constructor with the signature: - * public CLASS(JSONObject jsonObject). + * public CLASS(JSONObject jsonObject). * Fields must be primitives ONLY if they are to be stringifiable and override toString. */ public abstract class Message { - public interface JSONKey {} + public interface JSONKey {} - public enum Key implements JSONKey { - TYPE("type"); + public enum Key implements JSONKey { + TYPE("type"); - public final String key; + public final String key; - Key(final String key) { - this.key = key; - } + Key(final String key) { + this.key = key; + } - @Override - public String toString() {return key;} - } + @Override + public String toString() {return key;} + } - public enum Type { - LOCATION(0), - POST(1), - ROOM_INFO(2), - CLIENT_INFO(3); + public enum Type { + LOCATION(0), + POST(1), + ROOM_INFO(2), + CLIENT_INFO(3); - public final int type; + public final int type; - Type(final int type) { - this.type = type; - } + Type(final int type) { + this.type = type; + } - @Override - public String toString() {return Integer.toString(type);} - } + @Override + public String toString() {return Integer.toString(type);} + } - public enum Request { - LOCATION("{\"" + Key.TYPE + "\": " + Type.ROOM_INFO + '}'), - ROOM_INFO("{\"" + Key.TYPE + "\": " + Type.ROOM_INFO + '}'); + public enum Request { + LOCATION("{\"" + Key.TYPE + "\": " + Type.ROOM_INFO + '}'), + ROOM_INFO("{\"" + Key.TYPE + "\": " + Type.ROOM_INFO + '}'); - public final String request; + public final String request; - Request(final String request) { - this.request = request; - } + Request(final String request) { + this.request = request; + } - @Override - public String toString() {return request;} - } + @Override + public String toString() {return request;} + } - public static Type typeFromJson(final JSONObject message) { + public static Type typeFromJson(final JSONObject message) { if (message.containsKey(Key.TYPE.key) && message.get(Key.TYPE.key) instanceof Number) { int typeNumber = intFromJson(message, Key.TYPE); for (Type type : Type.values()) { @@ -65,7 +65,7 @@ public static Type typeFromJson(final JSONObject message) { } } return null; - } + } public static JSONObject jsonFromString(final String jsonString) { @@ -79,35 +79,35 @@ public static JSONObject jsonFromString(final String jsonString) { } } - /** - * - * NB: Does not enforce unique names. This should be enforced when storing the List (see: {@link Post#setTo(List) Post:setTo(List}). - * @param names - * @return True if the List is empty or all elements are valid names. False if List is longer than room max size. - */ - public static boolean validListOfNames(final List names) { - // Correctly allows for an empty array - if(names.size() == 0) {return true;} // Empty Lists are safe - if(names.size() > Client.NAMES.length) {return false;} // Cannot be larger than room max size - // ONLY check contents below here - - for(Object name : names.stream().distinct().toArray()) { // To remove DOS attack chance. - if (!(name instanceof String)) {return false;} - if (!Client.validName((String) (name))) {return false;} - } - return true; - } - - /** - * Helper method that encapsulates the casting of Numbers from JSONObjects. - * - * @haver.precondition jsonObject must contain key of type Number. - * @param jsonObject The entire JSONObject containing the key/value pair to extract and cast. - * @param key The key that maps to a Number in the jsonObject. - * @return The specified value as a double. - */ + /** + * + * NB: Does not enforce unique names. This should be enforced when storing the List (see: {@link Post#setTo(List) Post:setTo(List}). + * @param names + * @return True if the List is empty or all elements are valid names. False if List is longer than room max size. + */ + public static boolean validListOfNames(final List names) { + // Correctly allows for an empty array + if(names.size() == 0) {return true;} // Empty Lists are safe + if(names.size() > Client.NAMES.length) {return false;} // Cannot be larger than room max size + // ONLY check contents below here + + for(Object name : names.stream().distinct().toArray()) { // To remove DOS attack chance. + if (!(name instanceof String)) {return false;} + if (!Client.validName((String) (name))) {return false;} + } + return true; + } + + /** + * Helper method that encapsulates the casting of Numbers from JSONObjects. + * + * @haver.precondition jsonObject must contain key of type Number. + * @param jsonObject The entire JSONObject containing the key/value pair to extract and cast. + * @param key The key that maps to a Number in the jsonObject. + * @return The specified value as a double. + */ protected static double doubleFromJson(final JSONObject jsonObject, final JSONKey key) { - return ((Number) jsonObject.get(key.toString())).doubleValue(); + return ((Number) jsonObject.get(key.toString())).doubleValue(); } /** @@ -122,26 +122,26 @@ protected static int intFromJson(final JSONObject jsonObject, final JSONKey key) return ((Number) jsonObject.get(key.toString())).intValue(); } - /** - * Helper method that encapsulates the casting of Strings from JSONObjects. - * - * @haver.precondition jsonObject must contain key of type String. - * @param jsonObject The entire JSONObject containing the key/value pair to extract and cast. - * @param key The key that maps to a String in the jsonObject. - * @return The specified value as a String. - */ + /** + * Helper method that encapsulates the casting of Strings from JSONObjects. + * + * @haver.precondition jsonObject must contain key of type String. + * @param jsonObject The entire JSONObject containing the key/value pair to extract and cast. + * @param key The key that maps to a String in the jsonObject. + * @return The specified value as a String. + */ protected static String stringFromJson(final JSONObject jsonObject, final JSONKey key) { - return (String) jsonObject.get(key.toString()); + return (String) jsonObject.get(key.toString()); } - /** - * Helper method that encapsulates the casting of Lists from JSONObjects. - * - * @haver.precondition jsonObject must contain key of type List. - * @param jsonObject The entire JSONObject containing the key/value pair to extract and cast. - * @param key The key that maps to a List in the jsonObject. - * @return The specified value as a List. - */ + /** + * Helper method that encapsulates the casting of Lists from JSONObjects. + * + * @haver.precondition jsonObject must contain key of type List. + * @param jsonObject The entire JSONObject containing the key/value pair to extract and cast. + * @param key The key that maps to a List in the jsonObject. + * @return The specified value as a List. + */ protected static List listFromJson(final JSONObject jsonObject, final JSONKey key) { return (List) jsonObject.get(key.toString()); } diff --git a/src/main/java/chat/haver/server/Queue.java b/src/main/java/chat/haver/server/Queue.java index 321529c..1cec71b 100644 --- a/src/main/java/chat/haver/server/Queue.java +++ b/src/main/java/chat/haver/server/Queue.java @@ -4,85 +4,85 @@ import java.util.Date; public class Queue { - private final int rate; - private final long[] array; // array of epoch timestamps, or -1l - private int head = 0; // the index to insert the next element at - private int tail = 0; // the last element index + private final int rate; + private final long[] array; // array of epoch timestamps, or -1l + private int head = 0; // the index to insert the next element at + private int tail = 0; // the last element index - /** - * A queue of timestamps to be used in a rate limiting system. - * Efficient implementation using a circular array. - * - * @param capacity The maximum amount of messages that can be processed - * @param rate The time, in milliseconds, that the maximum amount of messages can be sent in - */ - public Queue(final int capacity, final int rate) { - array = new long[capacity]; - Arrays.fill(array, -1L); - this.rate = rate; - } + /** + * A queue of timestamps to be used in a rate limiting system. + * Efficient implementation using a circular array. + * + * @param capacity The maximum amount of messages that can be processed + * @param rate The time, in milliseconds, that the maximum amount of messages can be sent in + */ + public Queue(final int capacity, final int rate) { + array = new long[capacity]; + Arrays.fill(array, -1L); + this.rate = rate; + } - /** - * Adds a timestamp to the queue. - * - * @return False if the queue is full (rate limit has been hit), true if added successfully. - */ - public boolean add() { - final long now = new Date().getTime(); - if(isFull()) if (!clear(now)) return false; + /** + * Adds a timestamp to the queue. + * + * @return False if the queue is full (rate limit has been hit), true if added successfully. + */ + public boolean add() { + final long now = new Date().getTime(); + if(isFull()) if (!clear(now)) return false; - array[head] = now; - head = (head + 1) % array.length; - return true; - } + array[head] = now; + head = (head + 1) % array.length; + return true; + } - /** - * Checks to see if any space can be made in the array by moving expired timestamps. - * - * @param now The epoch timestamp now - * @return True if space was made, false otherwise - */ - public boolean clear(final long now) { - final long expireTime = now - rate; - final int startIndex = (head - 1 + array.length) % array.length; - int i = startIndex; - do { // moving backwards through the circle from the head - if(array[i] < expireTime) { - remove(tail, i); - tail = (i + 1) % array.length; - return true; - } - i = (i - 1 + array.length) % array.length; - } while(i != startIndex); + /** + * Checks to see if any space can be made in the array by moving expired timestamps. + * + * @param now The epoch timestamp now + * @return True if space was made, false otherwise + */ + public boolean clear(final long now) { + final long expireTime = now - rate; + final int startIndex = (head - 1 + array.length) % array.length; + int i = startIndex; + do { // moving backwards through the circle from the head + if(array[i] < expireTime) { + remove(tail, i); + tail = (i + 1) % array.length; + return true; + } + i = (i - 1 + array.length) % array.length; + } while(i != startIndex); - return false; - } + return false; + } - /** - * Checks to see if any space can be made in the array by moving expired timestamps. - * - * @return True if space was made, false otherwise - */ - public boolean clear() {return clear(new Date().getTime());} + /** + * Checks to see if any space can be made in the array by moving expired timestamps. + * + * @return True if space was made, false otherwise + */ + public boolean clear() {return clear(new Date().getTime());} - /** - * Helper method to 'remove' (set to -1l) a range of elements. - * Takes into account the circular nature of the array. - * - * @param fromIndex the first index to remove - * @param toIndex the last index to remove - */ - private void remove(final int fromIndex, final int toIndex) { - for(int i = fromIndex; i > toIndex; i = (i + 1) % array.length) {array[i] = -1L;} - } + /** + * Helper method to 'remove' (set to -1l) a range of elements. + * Takes into account the circular nature of the array. + * + * @param fromIndex the first index to remove + * @param toIndex the last index to remove + */ + private void remove(final int fromIndex, final int toIndex) { + for(int i = fromIndex; i > toIndex; i = (i + 1) % array.length) {array[i] = -1L;} + } - /** - * @return true if the array is empty, false otherwise - */ - public boolean isEmpty() {return (head == tail) && (array[tail] == -1L);} + /** + * @return true if the array is empty, false otherwise + */ + public boolean isEmpty() {return (head == tail) && (array[tail] == -1L);} - /** - * @return true if the array is full, false otherwise - */ - public boolean isFull() {return (head == tail) && (array[tail] != -1l);} + /** + * @return true if the array is full, false otherwise + */ + public boolean isFull() {return (head == tail) && (array[tail] != -1L);} } diff --git a/src/main/java/chat/haver/server/Room.java b/src/main/java/chat/haver/server/Room.java index 0b43d9f..2f48d9d 100644 --- a/src/main/java/chat/haver/server/Room.java +++ b/src/main/java/chat/haver/server/Room.java @@ -15,156 +15,156 @@ */ public class Room { - public static final String COMMAND_WHISPER = "whisper"; // TODO Move this command to client side? + public static final String COMMAND_WHISPER = "whisper"; // TODO Move this command to client side? - private static final Random RANDOM = new Random(); - private final String name; - private Location centre; - private final double radius; - private HashMap clients = new HashMap<>(); - private ArrayList freeNames = new ArrayList<>(Arrays.asList(Client.NAMES)); + private static final Random RANDOM = new Random(); + private final String name; + private Location centre; + private final double radius; + private HashMap clients = new HashMap<>(); + private ArrayList freeNames = new ArrayList<>(Arrays.asList(Client.NAMES)); - /** - * @param name The human-readable name of where the centre is. - * @param centre The Location of the centre of the Room. - * @param radius The distance in which a Client can join the Room. - */ - public Room(final String name, final Location centre, final double radius) { - if (Main.DEBUG && !(name.length() > 0)) { System.err.println("Room:Room() : Empty Name :^)"); } // TODO: null check and fix error message - this.name = name; - if (Main.DEBUG && !(centre != null)) { System.err.println("Room:Room() : Centre is null"); } // TODO: null check and fix error message - this.centre = centre; - if (Main.DEBUG && !(RoomInfo.validRadius(radius))) { System.err.println("Room:Room() : Invalid Radius"); } // TODO: null check and fix error message - this.radius = radius; // TODO Change as more people are added? - } + /** + * @param name The human-readable name of where the centre is. + * @param centre The Location of the centre of the Room. + * @param radius The distance in which a Client can join the Room. + */ + public Room(final String name, final Location centre, final double radius) { + if (Main.DEBUG && !(name.length() > 0)) { System.err.println("Room:Room() : Empty Name :^)"); } // TODO: null check and fix error message + this.name = name; + if (Main.DEBUG && !(centre != null)) { System.err.println("Room:Room() : Centre is null"); } // TODO: null check and fix error message + this.centre = centre; + if (Main.DEBUG && !(RoomInfo.validRadius(radius))) { System.err.println("Room:Room() : Invalid Radius"); } // TODO: null check and fix error message + this.radius = radius; // TODO Change as more people are added? + } - public Room(final RoomInfo roomInfo, final Location centre) { - this(roomInfo.getName(), centre, roomInfo.getRadius()); - } + public Room(final RoomInfo roomInfo, final Location centre) { + this(roomInfo.getName(), centre, roomInfo.getRadius()); + } - /** - * Adds a specified Client to the Room. - * - * @param conn The WebSocket of the specified Client. - * @param client The Client to be added. - */ - public void addClient(final WebSocket conn, final Client client) { - clients.put(conn, client); - client.setName(generateName()); // After .put to keep thread safe + /** + * Adds a specified Client to the Room. + * + * @param conn The WebSocket of the specified Client. + * @param client The Client to be added. + */ + public void addClient(final WebSocket conn, final Client client) { + clients.put(conn, client); + client.setName(generateName()); // After .put to keep thread safe centre = recalculateCentre(client.getLocation()); - conn.send(ClientInfo.toString(name, client.getName(), true, clients.values())); - String newClientString = ClientInfo.toString(true, client.getName()); - clients.forEach((k, v) -> { - if (k != conn) k.send(newClientString); - }); - System.out.println("Added conn [" + conn + "] to room [" + this + "]: "); - } + conn.send(ClientInfo.toString(name, client.getName(), true, clients.values())); + String newClientString = ClientInfo.toString(true, client.getName()); + clients.forEach((k, v) -> { + if (k != conn) k.send(newClientString); + }); + System.out.println("Added conn [" + conn + "] to room [" + this + "]: "); + } - /** - * Generate a client name that's unique to the room. - * A combination of things and colours. - */ - private String generateName() { - if(freeNames.size() == 0) { // TODO Actually handle this situation somehow - System.err.println("ROOM IS OVER MAXIMUM LIMIT, OH SHIT SON"); - System.exit(69); - } - int index = RANDOM.nextInt(freeNames.size()); - String name = freeNames.get(index); - freeNames.remove(index); - return name; - } + /** + * Generate a client name that's unique to the room. + * A combination of things and colours. + */ + private String generateName() { + if(freeNames.size() == 0) { // TODO Actually handle this situation somehow + System.err.println("ROOM IS OVER MAXIMUM LIMIT, OH SHIT SON"); + System.exit(69); + } + int index = RANDOM.nextInt(freeNames.size()); + String name = freeNames.get(index); + freeNames.remove(index); + return name; + } - /** - * Handler method for connection close. - * - * @param conn The socket which has been closed. - */ - public void close(final WebSocket conn) { + /** + * Handler method for connection close. + * + * @param conn The socket which has been closed. + */ + public void close(final WebSocket conn) { Client client = clients.get(conn); - freeNames.add(client.getName()); // Before .remove to keep thread safe - clients.remove(conn); + freeNames.add(client.getName()); // Before .remove to keep thread safe + clients.remove(conn); String removeClientString = ClientInfo.toString(false, client.getName()); clients.forEach((k, v) -> k.send(removeClientString)); - } + } - /** - * Sends the specified Post to the correct Clients in the Room. - * - * @param post The message to be broadcast. - */ + /** + * Sends the specified Post to the correct Clients in the Room. + * + * @param post The message to be broadcast. + */ @SuppressWarnings("checkstyle:finalparameters") - public void send(Post post) { - if(post.getContent().startsWith("/") && - (post = parseCommand(post)) == null) {return;} + public void send(Post post) { + if(post.getContent().startsWith("/") && + (post = parseCommand(post)) == null) {return;} // post may now be considered final - if (post.getTo().size() == 0) { - for (WebSocket conn : clients.keySet()) { - if (Main.DEBUG && !(validNames(post.getTo()) && conn.isOpen())) { System.err.println("Room:send() : Either name not valid or connection closed"); } // TODO: null check and fix error message - conn.send(post.toString()); - } - } else { - for(String name : post.getTo()) { - for(WebSocket conn : clients.keySet()) { - Client client = clients.get(conn); - if(client.getName().equals(name) || client.getName().equals(post.getFrom())) { - if (Main.DEBUG && !(validNames(post.getTo()) && conn.isOpen())) { System.err.println("Room:send() : Either name not valid or connection closed (2)"); } // TODO: null check and fix error message - conn.send(post.toString()); - break; - } - } - } - } - } + if (post.getTo().size() == 0) { + for (WebSocket conn : clients.keySet()) { + if (Main.DEBUG && !(validNames(post.getTo()) && conn.isOpen())) { System.err.println("Room:send() : Either name not valid or connection closed"); } // TODO: null check and fix error message + conn.send(post.toString()); + } + } else { + for(String name : post.getTo()) { + for(WebSocket conn : clients.keySet()) { + Client client = clients.get(conn); + if(client.getName().equals(name) || client.getName().equals(post.getFrom())) { + if (Main.DEBUG && !(validNames(post.getTo()) && conn.isOpen())) { System.err.println("Room:send() : Either name not valid or connection closed (2)"); } // TODO: null check and fix error message + conn.send(post.toString()); + break; + } + } + } + } + } - public Post parseCommand(final Post post) { - String[] splitContent = post.getContent().substring(1).split("\\s"); - String command = splitContent[0].toLowerCase(); - String[] args = Arrays.copyOfRange(splitContent, 1, splitContent.length); + public Post parseCommand(final Post post) { + String[] splitContent = post.getContent().substring(1).split("\\s"); + String command = splitContent[0].toLowerCase(); + String[] args = Arrays.copyOfRange(splitContent, 1, splitContent.length); - switch(command) { - // Implement commands here with a final static String - case(COMMAND_WHISPER): - if(!post.getFrom().equals(args[0])) { - post.setTo(args[0]); - post.setContent(post.getContent().substring(1 + command.length() + 1 + args[0].length() + 1)); - } else { - return null; // Cannot whisper to self - } - break; - default: - // No command found - return null; - } + switch(command) { + // Implement commands here with a final static String + case(COMMAND_WHISPER): + if(!post.getFrom().equals(args[0])) { + post.setTo(args[0]); + post.setContent(post.getContent().substring(1 + command.length() + 1 + args[0].length() + 1)); + } else { + return null; // Cannot whisper to self + } + break; + default: + // No command found + return null; + } - return post; - } + return post; + } - /** - * Handler method for Client Location update. - * - * @param client The Client whose Location is updated. - * @param location The updated Location of the specified Client. - */ - public void updateLocation(final Client client, final Location location) { - if (client.isValid()) { - //Location oldLocation = client.getLocation(); - client.setLocation(location); - //centre = recalculateCentre(oldLocation, location); - } else { - // Client dun goof'd? - } - } + /** + * Handler method for Client Location update. + * + * @param client The Client whose Location is updated. + * @param location The updated Location of the specified Client. + */ + public void updateLocation(final Client client, final Location location) { + if (client.isValid()) { + //Location oldLocation = client.getLocation(); + client.setLocation(location); + //centre = recalculateCentre(oldLocation, location); + } else { + // Client dun goof'd? + } + } - /** - * Helper method used to recalculate the centre of the room when a new client is added. - * Averages all the clients' locations. - * Accuracy is ignored. - * - * @param location The Location of the new Client. - */ - private Location recalculateCentre(final Location location) { + /** + * Helper method used to recalculate the centre of the room when a new client is added. + * Averages all the clients' locations. + * Accuracy is ignored. + * + * @param location The Location of the new Client. + */ + private Location recalculateCentre(final Location location) { if (centre == null) { return location; } else { @@ -176,84 +176,84 @@ private Location recalculateCentre(final Location location) { .collect(Collectors.toList()) ); } - } + } - /** - * Helper method used to recalculate the centre of the room when a client updates its location. - * Averages all the clients' locations. - * Accuracy is ignored. - * - * @param oldLocation The old Location of the Client. - * @param updatedLocation The Client's new Location. - */ + /** + * Helper method used to recalculate the centre of the room when a client updates its location. + * Averages all the clients' locations. + * Accuracy is ignored. + * + * @param oldLocation The old Location of the Client. + * @param updatedLocation The Client's new Location. + */ @Deprecated @SuppressWarnings("checkstyle:finalparameters") - private Location recalculateCentre(final Location oldLocation, Location updatedLocation) { - updatedLocation = recalculateCentre(updatedLocation); + private Location recalculateCentre(final Location oldLocation, Location updatedLocation) { + updatedLocation = recalculateCentre(updatedLocation); // updatedLocation can now be considered final - return new Location(updatedLocation.getLatitude() - (oldLocation.getLatitude() / clients.size()), - updatedLocation.getLongitude() - (oldLocation.getLongitude() / clients.size())); - } + return new Location(updatedLocation.getLatitude() - (oldLocation.getLatitude() / clients.size()), + updatedLocation.getLongitude() - (oldLocation.getLongitude() / clients.size())); + } - /** - * Helper method to check whether or not the specified location is within the range of the room. - * - * @param location The specified location. - * @return True if the specified location is within the radius of the room. - */ - public boolean inRange(final Location location) { + /** + * Helper method to check whether or not the specified location is within the range of the room. + * + * @param location The specified location. + * @return True if the specified location is within the radius of the room. + */ + public boolean inRange(final Location location) { return centre.distanceBetween(location) <= radius; - } + } - /** - * The name and number of Clients in the Room. - * - * @return name (numberOfClients) - */ - @Override - public String toString() { - return name + '(' + clients.size() + ')'; - } + /** + * The name and number of Clients in the Room. + * + * @return name (numberOfClients) + */ + @Override + public String toString() { + return name + '(' + clients.size() + ')'; + } - public Location getCentre() { - return centre; - } + public Location getCentre() { + return centre; + } - /** - * Checks if a name is in use in this Room. - * - * @param name The name to verify. - * @return True if the name is being used in the room. - */ - public boolean validName(final String name) { - for(Client client : clients.values()) { - if(client.getName().equals(name)) {return true;} - } - return false; + /** + * Checks if a name is in use in this Room. + * + * @param name The name to verify. + * @return True if the name is being used in the room. + */ + public boolean validName(final String name) { + for(Client client : clients.values()) { + if(client.getName().equals(name)) {return true;} + } + return false; - // Alternate implementation, which I believe will be slower: - // return Client.validName(name) && - // !freeNames.contains(name); - } + // Alternate implementation, which I believe will be slower: + // return Client.validName(name) && + // !freeNames.contains(name); + } - /** - * Checks if an array of names are in use in this Room. - * - * @param names The names to verify. - * @return True if all the names are being used in the room. - */ - public boolean validNames(final List names) { - for(String name : names) { - if(!validName(name)) {return false;} - } - return true; - } + /** + * Checks if an array of names are in use in this Room. + * + * @param names The names to verify. + * @return True if all the names are being used in the room. + */ + public boolean validNames(final List names) { + for(String name : names) { + if(!validName(name)) {return false;} + } + return true; + } - /** - * Getter for radius - * @return Radius - */ - public double getRadius() { - return radius; - } + /** + * Getter for radius + * @return Radius + */ + public double getRadius() { + return radius; + } } diff --git a/src/main/java/chat/haver/server/Router.java b/src/main/java/chat/haver/server/Router.java index 577c1f2..deba5d6 100644 --- a/src/main/java/chat/haver/server/Router.java +++ b/src/main/java/chat/haver/server/Router.java @@ -18,165 +18,165 @@ */ public class Router extends WebSocketServer { - public static final JSONParser PARSER = new JSONParser(); - private HashMap clients = new HashMap<>(); - private HashMap rooms = new HashMap<>(); - - - /** - * @throws UnknownHostException Config dun goof'd. - */ - public Router(final String hostname, final int port) throws UnknownHostException { - super(new InetSocketAddress(hostname, port)); - } - - @Override - public void onOpen(final WebSocket conn, final ClientHandshake handshake) { - Client client = new Client(); - clients.put(conn, client); + public static final JSONParser PARSER = new JSONParser(); + private HashMap clients = new HashMap<>(); + private HashMap rooms = new HashMap<>(); + + + /** + * @throws UnknownHostException Config dun goof'd. + */ + public Router(final String hostname, final int port) throws UnknownHostException { + super(new InetSocketAddress(hostname, port)); + } + + @Override + public void onOpen(final WebSocket conn, final ClientHandshake handshake) { + Client client = new Client(); + clients.put(conn, client); System.out.println("New connection (" + clients.size() + " connections): " + conn); - } + } - @Override - public void onClose(final WebSocket conn, final int code, final String reason, final boolean remote) { - Client client = clients.get(conn); - clients.remove(conn); + @Override + public void onClose(final WebSocket conn, final int code, final String reason, final boolean remote) { + Client client = clients.get(conn); + clients.remove(conn); if (rooms.get(client) != null) { rooms.get(client).close(conn); rooms.remove(client); } System.out.println("Connection closed(" + clients.size() + " remaining): " + conn); - } - - @Override - public void onError(final WebSocket conn, final Exception ex) { - ex.printStackTrace(); - if (conn != null) { - // some errors like port binding failed may not be assignable to a specific websocket - conn.close(); - } - } - - /** - * Accepts Stringified JSON of Messages and routes them accordingly. - * - * @param conn The WebSocket the Message was recieved on. - * @param message The Stringified JSON Message. - */ - @Override - public void onMessage(final WebSocket conn, final String message) { - Client client = clients.get(conn); - if (!client.addToQueue()) { - System.out.println("Messages too frequent, rate limiting: " + client.getName()); - return; - } - - Room room = rooms.get(client); - System.out.println("Message from [" + conn + "]: " + message); - - JSONObject jsonObject = Message.jsonFromString(message); - if (jsonObject == null) return; // invalid JSON - Message.Type type = Message.typeFromJson(jsonObject); - if (type == null) return; // invalid type - - if (room != null) { - switch (type) { - case LOCATION: - Location location = Location.fromJSON(jsonObject); - if (location == null) return; - if (room.inRange(client.getLocation())) { - room.updateLocation(client, location); - } else { - room.close(conn); - client.setLocation(location); - rooms.replace(client, getRoom(location)); - } - break; - - case POST: - room.send(Post.fromJSON(client, jsonObject)); - break; - - default: - System.out.println("Message from ["+conn+"] was invalid"); - // Client dun goof'd - break; - } - } else { - switch (type) { - case LOCATION: + } + + @Override + public void onError(final WebSocket conn, final Exception ex) { + ex.printStackTrace(); + if (conn != null) { + // some errors like port binding failed may not be assignable to a specific websocket + conn.close(); + } + } + + /** + * Accepts Stringified JSON of Messages and routes them accordingly. + * + * @param conn The WebSocket the Message was recieved on. + * @param message The Stringified JSON Message. + */ + @Override + public void onMessage(final WebSocket conn, final String message) { + Client client = clients.get(conn); + if (!client.addToQueue()) { + System.out.println("Messages too frequent, rate limiting: " + client.getName()); + return; + } + + Room room = rooms.get(client); + System.out.println("Message from [" + conn + "]: " + message); + + JSONObject jsonObject = Message.jsonFromString(message); + if (jsonObject == null) return; // invalid JSON + Message.Type type = Message.typeFromJson(jsonObject); + if (type == null) return; // invalid type + + if (room != null) { + switch (type) { + case LOCATION: Location location = Location.fromJSON(jsonObject); if (location == null) return; - client.setLocation(location); - room = getRoom(location); - if (room != null) { - setRoom(conn, client, room); - } else { - conn.send(Message.Request.ROOM_INFO.request); - System.out.println("Message to ["+conn+"]: "); - } - break; - - case ROOM_INFO: - if (client.getLocation() != null) { - RoomInfo roomInfo = RoomInfo.fromJSON(jsonObject); + if (room.inRange(client.getLocation())) { + room.updateLocation(client, location); + } else { + room.close(conn); + client.setLocation(location); + rooms.replace(client, getRoom(location)); + } + break; + + case POST: + room.send(Post.fromJSON(client, jsonObject)); + break; + + default: + System.out.println("Message from ["+conn+"] was invalid"); + // Client dun goof'd + break; + } + } else { + switch (type) { + case LOCATION: + Location location = Location.fromJSON(jsonObject); + if (location == null) return; + client.setLocation(location); + room = getRoom(location); + if (room != null) { + setRoom(conn, client, room); + } else { + conn.send(Message.Request.ROOM_INFO.request); + System.out.println("Message to ["+conn+"]: "); + } + break; + + case ROOM_INFO: + if (client.getLocation() != null) { + RoomInfo roomInfo = RoomInfo.fromJSON(jsonObject); if (roomInfo == null) return; - room = new Room(roomInfo, client.getLocation()); // TODO User input is only asserted and not validated properly - setRoom(conn, client, room); - } else { - // Client dun goof'd - conn.send(Message.Request.LOCATION.request); - System.out.println("Invalid room info from ["+conn+"]: "); - } - break; - - default: - // Client dun goof'd - conn.send(Message.Request.LOCATION.request); - System.out.println("Invalid message from ["+conn+"]: "); - break; - } - } - } - - /** - * Helper method that deals with showing a client to their specified room. - * - * @param conn The WebSocket of the client. - * @param client The client that needs to be put in a room. - * @param room The room that the client needs to be put in. - */ - private void setRoom(final WebSocket conn, final Client client, final Room room) { + room = new Room(roomInfo, client.getLocation()); // TODO User input is only asserted and not validated properly + setRoom(conn, client, room); + } else { + // Client dun goof'd + conn.send(Message.Request.LOCATION.request); + System.out.println("Invalid room info from ["+conn+"]: "); + } + break; + + default: + // Client dun goof'd + conn.send(Message.Request.LOCATION.request); + System.out.println("Invalid message from ["+conn+"]: "); + break; + } + } + } + + /** + * Helper method that deals with showing a client to their specified room. + * + * @param conn The WebSocket of the client. + * @param client The client that needs to be put in a room. + * @param room The room that the client needs to be put in. + */ + private void setRoom(final WebSocket conn, final Client client, final Room room) { if (rooms.get(client) != null) { rooms.replace(client, room); } else { rooms.put(client, room); } - room.addClient(conn, client); - } - - public Room getRoom(final Location location) { - double closest = Double.MAX_VALUE; - Room result = null; - for(Room room : new HashSet(rooms.values())) { - double distance = room.getCentre().distanceBetween(location); - if(distance < room.getRadius()) { - if(distance < closest) { - closest = distance; - result = room; - } - } - } - return result; - } - - /** - * Sends the specified message to every Room. - * @param post The Post to send - */ - public void broadcast(final Post post) { - for(Room room : rooms.values()) { - room.send(post); - } - } + room.addClient(conn, client); + } + + public Room getRoom(final Location location) { + double closest = Double.MAX_VALUE; + Room result = null; + for(Room room : new HashSet(rooms.values())) { + double distance = room.getCentre().distanceBetween(location); + if(distance < room.getRadius()) { + if(distance < closest) { + closest = distance; + result = room; + } + } + } + return result; + } + + /** + * Sends the specified message to every Room. + * @param post The Post to send + */ + public void broadcast(final Post post) { + for(Room room : rooms.values()) { + room.send(post); + } + } } diff --git a/src/main/java/chat/haver/server/package-info.java b/src/main/java/chat/haver/server/package-info.java new file mode 100644 index 0000000..c5e902f --- /dev/null +++ b/src/main/java/chat/haver/server/package-info.java @@ -0,0 +1,5 @@ +/** + * @see GitHub + * @see Javadoc + */ +package chat.haver.server;