/src/main/java/activitystreamer/server/Control.java
Java | 961 lines | 698 code | 112 blank | 151 comment | 160 complexity | 91c0ba8f0f090b610c1ffc247e3c1f7f MD5 | raw file
- package activitystreamer.server;
- import activitystreamer.Server;
- import activitystreamer.util.Settings;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.json.simple.JSONArray;
- import org.json.simple.JSONObject;
- import org.json.simple.parser.ParseException;
- import java.io.IOException;
- import java.net.Socket;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- /**
- * Class which handles controlling all connections
- */
- public class Control extends Thread {
- private static final Logger log = LogManager.getLogger();
- protected static Control control = null;
- private static ArrayList<Connection> connections;
- private static ArrayList<Client> clients;
- private static ArrayList<ServerInfo> servers;
- //TODO fill this arraylist @kinsey
- private static HashMap<Connection, ServerInfo> serverConnections;
- private static HashMap<Connection, Client> clientConnections;
- private static HashMap<String, RegisterLock> registerLocks;
- private static boolean term = false;
- private static Listener listener;
- private static Connection remoteServer;
- private static String ID;
- private Client anon;
- private Integer check = 0;
- public Control() {
- Server.starting = true;
- // Initialize maps which map connections to clients / servers
- this.ID = Settings.generateID();
- log.info("SERVER ID : " + this.ID);
- connections = new ArrayList<Connection>();
- clientConnections = new HashMap<Connection, Client>();
- serverConnections = new HashMap<Connection, ServerInfo>();
- registerLocks = new HashMap<String, RegisterLock>();
- //Initiate and add a client to the clients array
- clients = new ArrayList<Client>();
- //Anonymous client
- anon = new Client("anonymous", "null");
- clients.add(anon);
- //Initiate an outgoing connection to the first other server
- if (Settings.getRemoteHostname() != null) {
- initiateConnection(true, Settings.getRemoteHostname(), Settings.getRemotePort(), null);
- } else {
- log.info("First server in the network");
- }
- try {
- listener = new Listener();
- } catch (IOException e1) {
- log.fatal("failed to startup a listening thread: " + e1);
- System.exit(-1);
- }
- this.start();
- Server.starting = false;
- }
- public static Control getInstance() {
- while (Server.starting) {
- log.debug("Waiting on instantiation");
- continue;
- }
- if (control == null) {
- control = new Control();
- }
- return control;
- }
- /**
- * Connect to another server. Used to create the first connection and
- * then the subsequent connections once all the server info has been
- * received.
- *
- * @param initial if this is the first connection
- */
- public boolean initiateConnection(boolean initial, String remoteHost, int remotePort, String id) {
- log.info("Attempt connecting to : rp:" + remotePort + " rh : " + remoteHost);
- Socket socket;
- Connection remoteCon;
- try {
- socket = new Socket(remoteHost, remotePort);
- remoteCon = outgoingConnection(socket);
- OutgoingMessage authMsg;
- if (initial) {
- authMsg = new OutgoingMessage("AUTHENTICATE", Settings.getSecret(), this.ID, Settings.getLocalHostname(), Settings.getLocalPort());
- log.info("Sending init auth message: " + authMsg.getJsonReply());
- remoteCon.setAuthenticate(true);
- } else {
- authMsg = new OutgoingMessage("CONNECTION_REQUEST", Settings.getSecret(), this.ID, Settings.getLocalHostname(), Settings.getLocalPort());
- log.info("Sending connection request auth message: " + authMsg.getJsonReply());
- remoteCon.setAuthenticate(true);
- }
- remoteCon.writeMsg(authMsg.getJsonReply());
- connections.add(remoteCon);
- log.debug("adding new server");
- if (id != null) {
- ServerInfo authServer = new ServerInfo(remoteHost, remotePort, id);
- this.serverConnections.put(remoteCon, authServer);
- } else {
- ServerInfo authServer = new ServerInfo(remoteHost, remotePort);
- this.serverConnections.put(remoteCon, authServer);
- }
- return true;
- } catch (IOException e) {
- log.error("failed to make connection to " + Settings.getRemoteHostname() + ":" + Settings.getRemotePort() + " :" + e);
- return false;
- }
- }
- /**
- * Authenticates an incoming server connection.
- *
- * @return
- * @throws IOException
- */
- private boolean authenticateServer(boolean initial, Connection con, IncomingMessage incoming) {
- //check if secret is correct and its not already an authenticated server
- String secret = incoming.jsonMessage.get("secret").toString();
- String host = incoming.jsonMessage.get("lh").toString();
- String ID = incoming.jsonMessage.get("id").toString();
- int port = Integer.parseInt(incoming.jsonMessage.get("port").toString());
- if (secret.equals(Settings.getSecret())) {
- con.setAuthenticate(true);
- con.setServer(true);
- ServerInfo authServer = new ServerInfo(host, port, ID);
- if (initial) {
- log.debug("SENDING AUTH_INFO MESSAGE");
- OutgoingMessage msg = new OutgoingMessage(serverConnections, clients, this.ID);
- con.writeMsg(msg.getJsonReply().toString());
- }
- //Send the auth server info then add it to the connections
- this.serverConnections.put(con, authServer);
- return true;
- }
- return false;
- }
- /**
- * Processes incoming server announce. Updates the serverInfo object
- * which is mapped to this connection.
- *
- * @param msg
- * @param con
- * @return
- */
- private boolean processAnnounce(IncomingMessage msg, Connection con) {
- if (con.isAuthenticated() && serverConnections.containsKey(con)) {
- ServerInfo announcingServer = serverConnections.get(con);
- String hostname = msg.jsonMessage.get("hostname").toString();
- String ID = msg.jsonMessage.get("id").toString();
- JSONArray clients = (JSONArray) msg.jsonMessage.get("clients");
- for (int i = 0; i < clients.size(); i++) {
- String username = clients.get(i).toString();
- announcingServer.setConnectedClient(username);
- }
- int port = Integer.parseInt(msg.jsonMessage.get("port").toString());
- int load = Integer.parseInt(msg.jsonMessage.get("load").toString());
- announcingServer.setHostname(hostname);
- announcingServer.setID(ID);
- announcingServer.setLoad(load);
- announcingServer.setPort(port);
- announcingServer.setValid(true);
- JSONArray servClients = (JSONArray) msg.jsonMessage.get("remoteServerDB");
- log.debug("Checking message number ");
- for (int i = 0; i < servClients.size(); i++) {
- JSONObject client = (JSONObject) servClients.get(i);
- String username = (String) client.get("clientUsername");
- Integer messageNumber = Integer.parseInt(client.get("messageNumber").toString());
- log.debug("Going through the current servers client connections now");
- for (Client clie : clientConnections.values()) {
- if (clie.getUsername().equals(username)) {
- log.debug("Check if condition on message number ");
- log.debug(messageNumber != clie.getMessageNumber());
- if (messageNumber != clie.getMessageNumber()) {
- MessageInfo retMsg = new MessageInfo();
- retMsg = clie.getFromMessageDB(messageNumber);
- while (retMsg != null) {
- log.debug("SENDING CORRECT MESSAGE ORDER");
- OutgoingMessage repeatMsg = new OutgoingMessage(
- "CORRECT_MESSAGE_ORDER", messageNumber + 1, retMsg
- );
- log.debug("Correct order message is " + repeatMsg.getJsonReply());
- con.writeMsg(repeatMsg.getJsonReply());
- retMsg = clie.getFromMessageDB(++messageNumber);
- try {
- wait(1000);
- } catch (Exception e) {
- }
- }
- }
- }
- }
- }
- return true;
- }
- return false;
- }
- /**
- * Processes an incoming login message and
- * returns the relevant OutgoingMessge type.
- *
- * @param msg
- * @param con
- * @return
- */
- private OutgoingMessage processLogin(IncomingMessage msg, Connection con) {
- String username, secret;
- // The following block ensures that a username and secret is sent by the client
- try {
- //Anonymous login
- username = msg.jsonMessage.get("username").toString();
- if (username.equals("anonymous")) {
- clientConnections.put(con, anon);
- con.setServer(false);
- return new OutgoingMessage("LOGIN_SUCCESS",
- " Unauthenticated login as : " + username);
- } else {
- secret = msg.jsonMessage.get("secret").toString();
- }
- } catch (Exception e) {
- return new OutgoingMessage("INVALID_MESSAGE",
- "No secret provided");
- }
- for (Client cli : clients) {
- if (cli.getUsername().equals(username)) {
- if (cli.getSecret().equals(secret)) {
- clientConnections.put(con, cli);
- return new OutgoingMessage("LOGIN_SUCCESS",
- "logged in as user " + username);
- } else {
- return new OutgoingMessage("LOGIN_FAILED",
- "incorrect secret - " + secret
- + " provided for user " + username);
- }
- }
- }
- return new OutgoingMessage("LOGIN_FAILED",
- "no registered user with username - " + username);
- }
- /**
- * Registers a new client, takes an incoming message
- * which has the type of register. Broadcasts the request
- * to other servers as a LOCK_REQUEST.
- * The user is not registered until LOCK_ALLOWED has come back
- * from every server
- *
- * @param incoming
- * @return
- */
- private boolean registerClient(IncomingMessage incoming, Connection con) {
- String username = incoming.jsonMessage.get("username").toString();
- String secret = incoming.jsonMessage.get("secret").toString();
- Boolean available = true;
- for (Client curClient : clients) {
- if (curClient.getUsername().equals(username)) {
- available = false;
- }
- }
- // If its locally available send out lock request
- if (available) {
- OutgoingMessage lockMessage = new OutgoingMessage("LOCK_REQUEST", username, secret);
- log.debug("BROADCASTING " + lockMessage.getJsonReply());
- broadcastActivity(lockMessage, false, true);
- registerLocks.put(username, new RegisterLock(new Client(username, secret), serverConnections.size(), con));
- return true;
- }
- return false;
- }
- /**
- * Checks the registered users if a user is already registered
- * -> used for lock requests
- *
- * @param incoming
- * @return
- */
- private boolean checkRegisteredUsers(IncomingMessage incoming) {
- String username = incoming.jsonMessage.get("username").toString();
- for (Client client : clients) {
- if (username.equals(client.getUsername())) {
- return false;
- }
- }
- return true;
- }
- public void activityMessageBroadcast(OutgoingMessage message, boolean client, boolean server) {
- if (!server) {
- for (Connection con : serverConnections.keySet()) {
- ServerInfo ser = serverConnections.get(con);
- if (ser.getMessageDB().containsKey(message.reply.get("clientUsername").toString())) {
- Integer prevMsgNumber = ser.getMessageDB().get(message.reply.get("clientUsername").toString());
- if (!((prevMsgNumber + 1) ==
- (Integer.parseInt(message.reply.get("messageNumber").toString())))) {
- /*Integer msgNumber = Integer.parseInt(message.reply.get("messageNumber").toString());
- if( ((check==0 || check==1) && ((msgNumber==2) || (msgNumber==3)))){
- check++;
- return;
- }
- if ( (msgNumber ==4) && (this.check ==0)){
- */
- log.debug("SENDING INCORRECT MESSAGE PROTOCOL");
- JSONObject incorrectOrder = new JSONObject();
- incorrectOrder.put("command", "INCORRECT_MESSAGE_ORDER");
- incorrectOrder.put("serverId", Control.ID);
- incorrectOrder.put("clientUsername", message.reply.get("clientUsername").toString());
- incorrectOrder.put("previousMsgNumber", prevMsgNumber);
- con.writeMsg(incorrectOrder.toJSONString());
- this.check++;
- return;
- }
- ser.getMessageDB().replace(message.reply.get("clientUsername").toString(),
- Integer.parseInt(message.reply.get("messageNumber").toString()));
- } else {
- ser.getMessageDB().put(message.reply.get("clientUsername").toString(),
- Integer.parseInt(message.reply.get("messageNumber").toString()));
- }
- }
- } else if (server) {
- for (Connection con : serverConnections.keySet()) {
- log.debug("broadcast to servers" + message.getJsonReply());
- con.writeMsg(message.getJsonReply());
- }
- }
- if (client) {
- log.debug("I AM DISPLAYING THE 4th MESSAGE");
- log.debug("THE MESSAGE IS " + message.getJsonReply());
- JSONArray snapshot = (JSONArray) message.reply.get("snapshot");
- for (int i = 0; i < snapshot.size(); i++) {
- JSONObject serverClients = (JSONObject) snapshot.get(i);
- log.debug("EVERY SERVER ID " + serverClients.get("SID").toString());
- if (serverClients.get("SID").toString().equals(Control.ID)) {
- log.debug("I AM IN THE SERVER AND NOW PREPARED TO SEND THE MESSAGE");
- JSONArray clients = (JSONArray) serverClients.get("Clients");
- for (int j = 0; j < clients.size(); j++) {
- log.debug("The client array is " + clients.toJSONString());
- for (Connection con : clientConnections.keySet()) {
- log.debug("CHECK IF CONDITION");
- log.debug(clientConnections.get(con).getUsername().equals(clients.get(j).toString()));
- if (clientConnections.get(con).getUsername().equals(clients.get(j).toString())) {
- JSONObject cliMsg = new JSONObject();
- cliMsg.put("command", "ACTIVITY_BROADCAST");
- cliMsg.put("activity", message.reply.get("activity"));
- log.error("broadcast to client " + clients.get(j).toString() + " "
- + message.getJsonReply());
- con.writeMsg(cliMsg.toJSONString());
- }
- }
- }
- }
- }
- }
- }
- /**
- * Function to broadcast a message to connected clients and servers
- *
- * @param message
- * @param client to indicate whether this message came from a client
- * or was broadcast from other servers.
- * @param server
- */
- public void broadcastActivity(OutgoingMessage message, boolean client, boolean server) {
- if (client) {
- for (Connection con : clientConnections.keySet()) {
- log.debug("broadcast to clients" + message.getJsonReply());
- con.writeMsg(message.getJsonReply());
- }
- }
- if (server) {
- for (Connection con : serverConnections.keySet()) {
- log.debug("broadcast to servers" + message.getJsonReply());
- con.writeMsg(message.getJsonReply());
- }
- }
- }
- /**
- * Function which takes the incoming message and processes it. Sends a
- * connection too all other servers its connecting to.
- *
- * @return
- */
- public void processAuthenticationInfo(IncomingMessage message) {
- JSONArray clients = (JSONArray) message.jsonMessage.get("clients");
- JSONArray servers = (JSONArray) message.jsonMessage.get("servers");
- log.debug(message.toString());
- for (int i = 0; i < servers.size(); i++) {
- JSONObject server = (JSONObject) servers.get(i);
- String rh = server.get("rh").toString();
- String id = server.get("id").toString();
- int rp = Integer.parseInt(server.get("rp").toString());
- initiateConnection(false, rh, rp, id);
- }
- for (int i = 0; i < clients.size(); i++) {
- JSONObject jsonClient = (JSONObject) clients.get(i);
- String username = jsonClient.get("username").toString();
- String secret = jsonClient.get("secret").toString();
- Client client = new Client(username, secret);
- clients.add(client);
- }
- }
- /**
- * Main process function. This method checks the type of message by using
- * the IncomingMessage class. Depending on type, it delegates work and
- * decides whether to respond, close or maintain the connection
- *
- * @param con
- * @param msg
- * @return
- * @throws IOException
- * @throws ParseException
- */
- public synchronized boolean process(Connection con, String msg) {
- //TODO we need to work out if we want to throw and exception or
- //TODO or try catch each writeMsg()
- if (!term) {//in connection
- IncomingMessage incoming = new IncomingMessage(msg, con);
- if (incoming.type == IncomingMessage.Type.AUTHENTICATE) {
- if (con.isAuthenticated()) {
- con.writeMsg(new OutgoingMessage("INVALID_MESSAGE",
- "server already Authenticated").getJsonReply());
- removeConnections(con);
- return true;
- }
- String secret = incoming.jsonMessage.get("secret").toString();
- if (authenticateServer(true, con, incoming)) {
- log.info("AUTH_REQUEST FROM server with secret: " + secret);
- return false;
- }
- con.writeMsg(new OutgoingMessage("AUTHENTICATION_FAIL", secret).getJsonReply());
- log.info(con + "failed to authenticate with : " + secret + " actual : " + Settings.getSecret());
- removeConnections(con);
- return true;
- } else if (incoming.type == IncomingMessage.Type.AUTHENTICATE_INFO) {
- log.debug("INCOMING AUTHENTICATION INFO");
- processAuthenticationInfo(incoming);
- serverConnections.get(con).setID(incoming.jsonMessage.get("id").toString());
- return false;
- } else if (incoming.type == IncomingMessage.Type.CONNECTION_REQUEST) {
- if (con.isAuthenticated()) {
- con.writeMsg(new OutgoingMessage("INVALID_MESSAGE",
- "server already Authenticated").getJsonReply());
- removeConnections(con);
- return true;
- }
- String secret = incoming.jsonMessage.get("secret").toString();
- if (authenticateServer(false, con, incoming)) {
- log.info("AUTH_REQUEST FROM server with secret: " + secret);
- return false;
- }
- return true;
- } else if (incoming.type == IncomingMessage.Type.LOGIN) {
- if (con.isAuthenticated()) {
- OutgoingMessage message = new OutgoingMessage("INVALID_MESSAGE", "Already logged in. ");
- con.writeMsg(message.getJsonReply());
- removeConnections(con);
- return true;
- }
- OutgoingMessage validLoginmsg = processLogin(incoming, con);
- if (validLoginmsg.reply.get("command").equals("LOGIN_SUCCESS")) {
- for (Connection servCon : serverConnections.keySet()) {
- ServerInfo serv = serverConnections.get(servCon);
- //If our server has 2 more connected clients
- //send it a redirect
- if (clientConnections.size() >= 3 + serv.getLoad() && serv.isValid()) {
- con.writeMsg(validLoginmsg.getJsonReply());
- con.writeMsg(new OutgoingMessage("REDIRECT",
- serv.getHostname(), serv.getPort().toString()).getJsonReply());
- removeConnections(con);
- return true;
- }
- }
- con.setAuthenticate(true);
- con.writeMsg(validLoginmsg.getJsonReply());
- return false;
- } else {
- //send message back to client accordingly
- con.writeMsg(validLoginmsg.getJsonReply());
- removeConnections(con);
- return true;
- }
- } else if (incoming.type == IncomingMessage.Type.LOGOUT) {
- removeConnections(con);
- return true;
- } else if (incoming.type == IncomingMessage.Type.DISCONNECT_CLIENT) {
- log.debug("WITHING DISCONNECT_CLIENT");
- for (ServerInfo server : serverConnections.values()) {
- log.debug("iterating through server connections");
- log.debug(server.getID().equals(incoming.jsonMessage.get("serverId").toString()));
- if (server.getID().equals(incoming.jsonMessage.get("serverId").toString())) {
- server.removeFromStorage(incoming.jsonMessage.get("clientUsername").toString());
- }
- }
- return false;
- } else if (incoming.type == IncomingMessage.Type.INVALID) {
- OutgoingMessage message = new OutgoingMessage("INVALID_MESSAGE", incoming.invalidString);
- con.writeMsg(message.getJsonReply());
- removeConnections(con);
- return true;
- } else if (incoming.type == IncomingMessage.Type.AUTHENTICATION_FAIL) {
- log.debug("Tried to connect.. but failed");
- removeConnections(con);
- return true;
- } else if (incoming.type == IncomingMessage.Type.REGISTER) {
- String username = incoming.jsonMessage.get("username").toString();
- if (registerClient(incoming, con)) {
- log.debug("INCOMING REGISTER : " + incoming.jsonMessage.toJSONString());
- //If this is the first server
- if (registerLocks.get(username).status()) {
- OutgoingMessage message = new OutgoingMessage("REGISTER_SUCCESS", username + " registered successfully");
- con.writeMsg(message.getJsonReply());
- }
- return false;
- } else {
- con.writeMsg(new OutgoingMessage("REGISTER_FAILED", "").getJsonReply());
- removeConnections(con);
- return true;
- }
- } else if (incoming.type == IncomingMessage.Type.SERVER_ANNOUNCE) {
- log.info("Received server announce : ");
- log.info(con.getSocket().getRemoteSocketAddress());
- if (processAnnounce(incoming, con)) {
- return false;
- } else {
- con.writeMsg(new OutgoingMessage("INVALID_MESSAGE",
- "Invalid server announce").getJsonReply());
- removeConnections(con);
- return true;
- }
- } else if (incoming.type == IncomingMessage.Type.ACTIVITY_MESSAGE) {
- JSONObject activity = (JSONObject) incoming.jsonMessage.get("activity");
- if (con.isAuthenticated()) {
- Client cli = clientConnections.get(con);
- if (((cli.getUsername().equals(incoming.jsonMessage.get("username")))
- && (cli.getSecret().equals(incoming.jsonMessage.get("secret"))))
- || incoming.jsonMessage.get("username").equals("anonymous")) {
- String username = clientConnections.get(con).getUsername();
- activity.put("authenticated_user", username);
- MessageInfo message = new MessageInfo(
- this.generateSnapShot(), Control.ID, cli.getUsername(), activity);
- log.debug("PRINTING MESSAGE INFORMATION");
- log.debug("SNAPSHOT : " + message.getSnapshot().toJSONString());
- cli.addToMessageDB(message);
- OutgoingMessage abMessage =
- new OutgoingMessage("ACTIVITY_BROADCAST",
- cli.getMessageNumber(), message);
- /*OutgoingMessage activityBroadcastMessage =
- new OutgoingMessage("ACTIVITY_BROADCAST",
- activity);
- */
- activityMessageBroadcast(abMessage, true, true);
- //broadcastActivity(abMessage, true, true);
- return false;
- } else {
- OutgoingMessage outgoingMessage = new OutgoingMessage(
- "AUTHENTICATION_FAIL", "Incorrect secret or username provided"
- );
- removeConnections(con);
- con.writeMsg(outgoingMessage.getJsonReply());
- return true;
- }
- } else {
- OutgoingMessage outgoingMessage = new OutgoingMessage(
- "AUTHENTICATION_FAIL", "Not Logged In"
- );
- removeConnections(con);
- con.writeMsg(outgoingMessage.getJsonReply());
- return true;
- }
- } else if (incoming.type == IncomingMessage.Type.ACTIVITY_BROADCAST) {
- if (con.isAuthenticated()) {
- log.debug("ACTIVITY MESSAGE COMING IN");
- log.debug(incoming.jsonMessage.toString());
- MessageInfo message = new MessageInfo(
- (JSONArray) incoming.jsonMessage.get("snapshot"),
- (String) incoming.jsonMessage.get("serverId"),
- (String) incoming.jsonMessage.get("clientUsername"),
- (JSONObject) incoming.jsonMessage.get("activity")
- );
- OutgoingMessage outgoing = new OutgoingMessage("ACTIVITY_BROADCAST",
- Integer.parseInt(incoming.jsonMessage.get("messageNumber").toString()), message);
- //TODO unpack the broadcast and send without the message info
- activityMessageBroadcast(outgoing, true, false);
- return false;
- } else {
- new OutgoingMessage("INVALID_MESSAGE", "Unauthenticated Server");
- removeConnections(con);
- return true;
- }
- } else if (incoming.type == IncomingMessage.Type.LOCK_REQUEST) {
- String username = incoming.jsonMessage.get("username").toString();
- String secret = incoming.jsonMessage.get("secret").toString();
- if (checkRegisteredUsers(incoming)) {
- clients.add(new Client(username, secret));
- broadcastActivity(
- new OutgoingMessage("LOCK_ALLOWED", username, secret),
- false, true);
- } else {
- broadcastActivity(
- new OutgoingMessage("LOCK_DENIED", username, secret),
- false, true);
- }
- } else if (incoming.type == IncomingMessage.Type.LOCK_DENIED) {
- String username = incoming.jsonMessage.get("username").toString();
- if (registerLocks.containsKey(username)) {
- registerLocks.remove(username);
- OutgoingMessage message = new OutgoingMessage("REGISTER_FAILED", username + " is already registered");
- con.writeMsg(message.getJsonReply());
- removeConnections(con);
- return true;
- }
- Iterator<Client> clientsIt = clients.iterator();
- while (clientsIt.hasNext()) {
- if (clientsIt.next().getUsername().equals(username)) {
- clientsIt.remove();
- }
- }
- return false;
- } else if (incoming.type == IncomingMessage.Type.LOCK_ALLOWED) {
- String username = incoming.jsonMessage.get("username").toString();
- if (registerLocks.containsKey(username)) {
- RegisterLock lock = registerLocks.get(username);
- lock.addAllowed();
- if (lock.status()) {
- clients.add(lock.getClient());
- OutgoingMessage message = new OutgoingMessage("REGISTER_SUCCESS", username + " registered successfully");
- lock.getCon().writeMsg(message.getJsonReply());
- }
- }
- } else if (incoming.type == IncomingMessage.Type.INCORRECT_MESSAGE_ORDER) {
- log.debug("RECEIVING INCORRECT MESSAGE PROTOCOL");
- for (Connection cliCon : clientConnections.keySet()) {
- Client cli = clientConnections.get(cliCon);
- if (cli.getUsername().equals(incoming.jsonMessage.get("clientUsername").toString())) {
- MessageInfo retMsg = new MessageInfo();
- Integer prevNumber = Integer.parseInt(incoming.jsonMessage.get("previousMsgNumber").toString());
- retMsg = cli.getFromMessageDB(prevNumber);
- while (retMsg != null) {
- int count = 0;
- for (Connection serCon : serverConnections.keySet()) {
- ServerInfo ser = serverConnections.get(serCon);
- if (ser.getID().equals(incoming.jsonMessage.get("serverId").toString())) {
- log.debug("SENDING CORRECT MESSAGE ORDER");
- OutgoingMessage repeatMsg = new OutgoingMessage(
- "CORRECT_MESSAGE_ORDER", prevNumber + 1, retMsg
- );
- count++;
- serCon.writeMsg(repeatMsg.getJsonReply());
- retMsg = cli.getFromMessageDB(++prevNumber);
- try {
- wait(1000);
- } catch (Exception e) {
- }
- }
- }
- if (count == 0)
- retMsg = null;
- }
- }
- }
- return false;
- } else if (incoming.type == IncomingMessage.Type.CORRECT_MESSAGE_ORDER) {
- /*JSONArray snapshot = new JSONArray();
- JSONObject servCli = new JSONObject();
- JSONArray cli = new JSONArray();
- for (Connection c : clientConnections.keySet()){
- Client cliCon = clientConnections.get(c);
- cli.add(cliCon.getUsername());
- }
- servCli.put("Clients",cli);
- servCli.put("SID",Control.ID);
- snapshot.add(servCli);
- */
- MessageInfo message = new MessageInfo(
- (JSONArray) incoming.jsonMessage.get("snapshot"),
- (String) incoming.jsonMessage.get("serverId"),
- (String) incoming.jsonMessage.get("clientUsername"),
- (JSONObject) incoming.jsonMessage.get("activity")
- );
- OutgoingMessage outgoing = new OutgoingMessage("ACTIVITY_BROADCAST",
- Integer.parseInt(incoming.jsonMessage.get("messageNumber").toString()), message);
- log.debug("THIS IS THE 4th MESSAGE " + outgoing.getJsonReply());
- activityMessageBroadcast(outgoing, true, false);
- return false;
- }
- return false;
- }
- return false;
- }
- /*
- * The connection has been closed by the other party.
- */
- public synchronized void connectionClosed(Connection con) {
- if (!term) connections.remove(con);
- }
- /**
- * Creates a new connection type for incoming socket connections
- *
- * @param s
- * @return
- * @throws IOException
- */
- public synchronized Connection incomingConnection(Socket s) throws IOException {
- log.debug("incoming connection: " + Settings.socketAddress(s));
- Connection c = new Connection(s);
- connections.add(c);
- return c;
- }
- /**
- * A new outgoing connection has been established, and a reference is returned to it
- *
- * @param s
- * @return
- * @throws IOException
- */
- public synchronized Connection outgoingConnection(Socket s) throws IOException {
- log.debug("outgoing connection: " + Settings.socketAddress(s));
- Connection c = new Connection(s);
- connections.add(c);
- return c;
- }
- /**
- * Overridden run method to allow the broadcasting to happen in a separate
- * thread to the incoming message processing.
- */
- @Override
- public void run() {
- log.info("using activity interval of " + Settings.getActivityInterval() + " milliseconds");
- while (!term) {
- // do something with 5 second intervals in between
- try {
- Thread.sleep(Settings.getActivityInterval());
- } catch (InterruptedException e) {
- log.info("Received an interrupt, system is shutting down");
- break;
- }
- if (!term) {
- logInfo();
- term = broadcastServerAnnounce();
- }
- }
- log.info("closing " + connections.size() + " connections");
- // clean up
- for (Connection connection : connections) {
- connection.closeCon();
- }
- listener.setTerm(true);
- }
- public void logInfo() {
- log.info("Current server list: ");
- for (Connection servConnection : serverConnections.keySet()) {
- ServerInfo server = serverConnections.get(servConnection);
- log.info("Server : " + server.getID() +
- " load: " + server.getLoad() +
- " Client Messages " + server.getMessageDB().toString());
- server.printConnectedClients();
- }
- log.info("Connected client list: ");
- for (Connection clientConnection : clientConnections.keySet()) {
- log.info(clientConnections.get(clientConnection).getUsername());
- }
- log.debug("Known client list: ");
- for (Client client : clients) {
- log.info(client.getUsername());
- }
- }
- /**
- * Activity function for announcing servers
- *
- * @return
- */
- private boolean broadcastServerAnnounce() {
- ArrayList<Client> connectedClients = new ArrayList<>(clientConnections.values());
- for (Connection connection : serverConnections.keySet()) {
- ServerInfo server = serverConnections.get(connection);
- HashMap<String, Integer> db = new HashMap<String, Integer>();
- db = server.getMessageDB();
- JSONArray serverClients = new JSONArray();
- for (String username : db.keySet()) {
- JSONObject cli = new JSONObject();
- cli.put("clientUsername", username);
- cli.put("messageNumber", db.get(username));
- serverClients.add(cli);
- }
- String msg = new OutgoingMessage("SERVER_ANNOUNCE",
- this.ID, clientConnections.size() + "",
- Settings.getLocalHostname(),
- Settings.getLocalPort() + "", connectedClients, serverClients).getJsonReply();
- if (connection.isOpen())
- connection.writeMsg(msg);
- }
- return false;
- }
- public HashMap<String, ArrayList<String>> generateSnapShot() {
- ArrayList<String> cliUsernames = new ArrayList<String>();
- for (Connection con : clientConnections.keySet()) {
- Client cli = clientConnections.get(con);
- cliUsernames.add(cli.getUsername());
- }
- HashMap<String, ArrayList<String>> snapShot = new HashMap<String, ArrayList<String>>();
- for (Connection con : serverConnections.keySet()) {
- ServerInfo server = serverConnections.get(con);
- snapShot.put(server.getID(), server.getConnectedClients());
- }
- snapShot.put(Control.ID, cliUsernames);
- return snapShot;
- }
- public final void setTerm(boolean t) {
- term = t;
- }
- public final ArrayList<Connection> getConnections() {
- return connections;
- }
- public void removeConnections(Connection con) {
- if (clientConnections.containsKey(con)) {
- Client cli = clientConnections.get(con);
- OutgoingMessage outgoing = new OutgoingMessage("DISCONNECT_CLIENT", Control.ID, cli.getUsername());
- broadcastActivity(outgoing, false, true);
- clientConnections.remove(con);
- }
- if (serverConnections.containsKey(con))
- serverConnections.remove(con);
- }
- public ServerInfo getServer(Connection con) {
- return this.serverConnections.get(con);
- }
- /**
- * Function which reconnects to a socket
- * It removes the old connection and then
- * creates a new connection object
- *
- * @param oldCon
- * @param badServer
- * @param socket
- */
- public void resetConnection(Connection oldCon, ServerInfo badServer, Socket socket) {
- try {
- Connection newCon = this.outgoingConnection(socket);
- serverConnections.remove(oldCon);
- serverConnections.put(newCon, badServer);
- log.debug("SENDING RECONNECT REQUEST");
- OutgoingMessage authMsg = new OutgoingMessage("CONNECTION_REQUEST",
- Settings.getSecret(), this.ID, Settings.getLocalHostname(), Settings.getLocalPort());
- newCon.writeMsg(authMsg.getJsonReply());
- newCon.setAuthenticate(true);
- oldCon.closeCon();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }