diff --git a/Controller.java b/Controller.java index 1da9704e17bb11d075d3cd8cc652ea297c1b3a93..9de796fbe335ead0d60f6204b3e8530c97dca958 100644 --- a/Controller.java +++ b/Controller.java @@ -100,63 +100,6 @@ public class Controller { public long filesize; } - //Rebalances only start when there are no executing threads - protected class RebalanceLock { - protected int processes; - protected boolean highPriorityWait; - protected CountDownLatch periodBlock; - protected Object blockLock; - - public RebalanceLock() { - periodBlock = new CountDownLatch(1); - blockLock = new Object(); - } - - public synchronized void addProcess() throws InterruptedException { - while(highPriorityWait) { - this.wait(); - } - - processes ++; - } - - public synchronized void removeProcess() { - processes --; - if(processes == 0) this.notifyAll(); - } - - public void waitForFinish() { - while(processes > 0) { - highPriorityWait = true; - try { - this.wait(); - } - catch(InterruptedException e) {e.printStackTrace();} - } - highPriorityWait = false; - } - - public void queueRebalance() { - synchronized(blockLock) { - periodBlock.countDown(); - } - } - - public boolean waitToRebalance() { - try { - boolean dstoreJoined = periodBlock.await(rebalancePeriod, TimeUnit.MILLISECONDS); - if(dstoreJoined) { - synchronized(blockLock) { - periodBlock = new CountDownLatch(1); - } - } - return dstoreJoined; - } - catch(InterruptedException e) {e.printStackTrace();} - return true; - } - } - protected Map<Integer,DstoreConnection> dstores; protected RebalanceMessages rebalanceMessages; protected Map<String,IndexEntry> index; @@ -173,7 +116,9 @@ public class Controller { rebalanceMessages = new RebalanceMessages(); index = Collections.synchronizedMap(new HashMap<String,IndexEntry>()); loadRequests = Collections.synchronizedMap(new HashMap<Socket,Reloader>()); - rebalanceLock = new RebalanceLock(); + rebalanceLock = new RebalanceLock(rebalancePeriod); + + try {ControllerLogger.init(Logger.LoggingType.ON_FILE_AND_TERMINAL);} catch(IOException e) {e.printStackTrace();} } public static void main(String[] args) { @@ -215,16 +160,18 @@ public class Controller { Socket client = server.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); String tMessage = in.readLine(); + messageReceived(client, tMessage); String[] message; - if(tMessage == null) {message = new String[]{""};} + if(tMessage == null) {try {client.close();} catch(IOException e) {} finally {return;}} else {message = tMessage.split(" ");} new Thread(() -> { - if(message[0].equals("JOIN")) { + if(message[0].equals(Protocol.JOIN_TOKEN)) { int portNumber = Integer.parseInt(message[1]); synchronized(rebalanceLock) { dstores.put(portNumber, new DstoreConnection(client, portNumber, timeout)); System.out.println("Dstore at " + portNumber + " joined"); + ControllerLogger.getInstance().dstoreJoined(client, portNumber); rebalanceLock.queueRebalance(); } } @@ -241,7 +188,7 @@ public class Controller { do { try { clientMessage = in.readLine(); - System.out.println(clientMessage); + messageReceived(client, clientMessage); if(clientMessage != null) { handleMessage(clientMessage.split(" "), client); } @@ -273,9 +220,11 @@ public class Controller { public void run() { while(true) { if(rebalanceLock.waitToRebalance()) { + //Another dstore joined, it requested a rebalance try {runRebalance();} catch(Exception e) {e.printStackTrace();} } else { + //Timeout occured, i.e. rebalancePeriod has passed since the last rebalance try { if(dstores.size() >= rFactor) { runRebalance(); @@ -304,22 +253,23 @@ public class Controller { try { if(dstores.size() < rFactor) { PrintWriter out = new PrintWriter(client.getOutputStream()); - out.println("ERROR_NOT_ENOUGH_DSTORES"); + out.println(Protocol.ERROR_NOT_ENOUGH_DSTORES_TOKEN); out.flush(); + messageSent(client, Protocol.ERROR_NOT_ENOUGH_DSTORES_TOKEN); } - else if(message[0].equals("STORE")) { + else if(message[0].equals(Protocol.STORE_TOKEN)) { store(client, message[1], message[2]); } - else if(message[0].equals("LOAD")) { + else if(message[0].equals(Protocol.LOAD_TOKEN)) { load(client, message[1]); } - else if(message[0].equals("RELOAD")) { + else if(message[0].equals(Protocol.RELOAD_TOKEN)) { sendLoadFrom(client, message[1]); } - else if(message[0].equals("REMOVE")) { + else if(message[0].equals(Protocol.REMOVE_TOKEN)) { remove(client, message[1]); } - else if(message[0].equals("LIST")) { + else if(message[0].equals(Protocol.LIST_TOKEN)) { list(client); } else { @@ -364,8 +314,9 @@ public class Controller { } else { PrintWriter out = new PrintWriter(client.getOutputStream()); - out.println("ERROR_FILE_ALREADY_EXISTS " + filename); + out.println(Protocol.ERROR_FILE_ALREADY_EXISTS_TOKEN); out.flush(); + messageSent(client, Protocol.ERROR_FILE_ALREADY_EXISTS_TOKEN); return; } } @@ -386,13 +337,13 @@ public class Controller { //Send STORE_TO message CyclicBarrier barrier = new CyclicBarrier(rFactor + 1); PrintWriter out = new PrintWriter(client.getOutputStream()); - String message = "STORE_TO"; + String message = Protocol.STORE_TO_TOKEN; for(Integer thisStore : storesToStore) { message = message + " " + thisStore.intValue(); new Thread(() -> { try { - String[] receivedMessage = dstores.get(thisStore).receive("STORE_ACK").split(" "); - if(receivedMessage[0].equals("STORE_ACK")) { + String[] receivedMessage = dstores.get(thisStore).receive(Protocol.STORE_ACK_TOKEN).split(" "); + if(receivedMessage[0].equals(Protocol.STORE_ACK_TOKEN)) { try { storeAck(thisStore, receivedMessage[1], barrier); } @@ -446,8 +397,9 @@ public class Controller { entry.status = IndexEntry.Status.STORE_COMPLETE; //Send STORE_COMPLETE message - out.println("STORE_COMPLETE"); + out.println(Protocol.STORE_COMPLETE_TOKEN); out.flush(); + messageSent(client, Protocol.STORE_COMPLETE_TOKEN); } catch(IOException e) { e.printStackTrace(); @@ -475,8 +427,9 @@ public class Controller { try { if(!index.containsKey(filename) || index.get(filename).status != IndexEntry.Status.STORE_COMPLETE) { PrintWriter out = new PrintWriter(client.getOutputStream()); - out.println("ERROR DOES_NOT_EXIST"); + out.println(Protocol.ERROR_FILE_DOES_NOT_EXIST_TOKEN); out.flush(); + messageSent(client, Protocol.ERROR_FILE_DOES_NOT_EXIST_TOKEN); return; } @@ -505,15 +458,18 @@ public class Controller { PrintWriter out = new PrintWriter(client.getOutputStream()); Reloader storedBy = loadRequests.get(client); System.out.println("Load requested for file " + filename + ", there are " + storedBy.size() + " dstores to select from"); + String message; if(storedBy.isEmpty()) { - out.println("ERROR_LOAD"); + message = Protocol.ERROR_LOAD_TOKEN; } else { Integer thisStore = storedBy.get(0); storedBy.remove(thisStore); - out.println("LOAD_FROM " + thisStore + " " + storedBy.filesize); + message = Protocol.LOAD_FROM_TOKEN + thisStore + " " + storedBy.filesize; } + out.println(message); out.flush(); + messageSent(client, message); } catch(IOException e) { e.printStackTrace(); @@ -524,8 +480,9 @@ public class Controller { try { if(!index.containsKey(filename) || index.get(filename).status != IndexEntry.Status.STORE_COMPLETE) { PrintWriter clientOut = new PrintWriter(client.getOutputStream()); - clientOut.println("ERROR DOES_NOT_EXIST"); + clientOut.println(Protocol.ERROR_FILE_DOES_NOT_EXIST_TOKEN); clientOut.flush(); + messageSent(client, Protocol.ERROR_FILE_DOES_NOT_EXIST_TOKEN); return; } @@ -538,8 +495,8 @@ public class Controller { for(Integer dstore : entry.getStoredBy()) { new Thread(() -> { try { - String[] message = dstores.get(dstore).sendAndReceive("REMOVE " + filename, "REMOVE_ACK").split(" "); - if(message[0].equals("REMOVE_ACK") && message[1].equals(filename)) { + String[] message = dstores.get(dstore).sendAndReceive(Protocol.REMOVE_TOKEN + " " + filename, Protocol.REMOVE_ACK_TOKEN).split(" "); + if(message[0].equals(Protocol.REMOVE_ACK_TOKEN) && message[1].equals(filename)) { entry.removeStoredBy(dstore.intValue()); try { barrier.await(); @@ -595,8 +552,9 @@ public class Controller { //Send REMOVE_COMPLETE to client PrintWriter clientOut = new PrintWriter(client.getOutputStream()); - clientOut.println("REMOVE_COMPLETE"); + clientOut.println(Protocol.REMOVE_COMPLETE_TOKEN); clientOut.flush(); + messageSent(client, Protocol.REMOVE_COMPLETE_TOKEN); } catch(IOException e) { e.printStackTrace(); @@ -607,7 +565,7 @@ public class Controller { try { System.out.println("Fetching list..."); //Send file list to client - String message = "LIST "; + String message = Protocol.LIST_TOKEN + " "; for(String name : index.keySet()) { if(index.get(name).status == IndexEntry.Status.STORE_COMPLETE) message = message + name + " "; } @@ -615,6 +573,7 @@ public class Controller { System.out.println("Sending..."); out.println(message.trim()); out.flush(); + messageSent(client, message.trim()); } catch(IOException e) { e.printStackTrace(); @@ -635,7 +594,7 @@ public class Controller { for(Integer dstore : dstores.keySet()) { new Thread(() -> { try { - String[] message = dstores.get(dstore).sendAndReceive("LIST").split(" "); + String[] message = dstores.get(dstore).sendAndReceive(Protocol.LIST_TOKEN).split(" "); receiveDstoreList(dstore.intValue(), message, barrier); } catch(DstoreDisconnectException e) { @@ -742,7 +701,7 @@ public class Controller { sendMessages.add(fileMessage); } - String message = "REBALANCE " + sendMessages.size(); + String message = Protocol.REBALANCE_TOKEN + " " + sendMessages.size(); for(String s : sendMessages) { message = message + " " + s; } @@ -757,8 +716,8 @@ public class Controller { new Thread(() -> { try { DstoreConnection connection = dstores.get(thisStore); - String returnMessage = connection.sendAndReceive(finalMessage, "REBALANCE_COMPLETE"); - if(!returnMessage.equals("REBALANCE_COMPLETE")) { + String returnMessage = connection.sendAndReceive(finalMessage, Protocol.REBALANCE_COMPLETE_TOKEN); + if(!returnMessage.equals(Protocol.REBALANCE_COMPLETE_TOKEN)) { //Log error System.out.println("Dstore " + thisStore + " should have sent REBALANCE_COMPLETE but Controller received " + returnMessage); } @@ -766,8 +725,8 @@ public class Controller { new Thread(() -> {try {barrier2.await();} catch(Exception e) {e.printStackTrace();}}).start(); for(int i=0; i<requireIndex.get(thisStore).size(); i++) { - returnMessage = connection.receive("STORE_ACK"); - if(!returnMessage.split(" ")[0].equals("STORE_ACK")) { + returnMessage = connection.receive(Protocol.STORE_ACK_TOKEN); + if(!returnMessage.split(" ")[0].equals(Protocol.STORE_ACK_TOKEN)) { //Log error System.out.println("Dstore " + thisStore + " should have sent STORE_ACK but Controller received " + returnMessage); } @@ -901,4 +860,12 @@ public class Controller { } return true; } + + void messageSent(Socket socket, String message) { + ControllerLogger.getInstance().messageSent(socket, message); + } + + void messageReceived(Socket socket, String message) { + ControllerLogger.getInstance().messageReceived(socket, message); + } } diff --git a/Dstore.java b/Dstore.java index 4bdde39763a54ff48a58c78cb531788628bf324a..6ac0414e86bcee2bc72705460698e365990318f8 100644 --- a/Dstore.java +++ b/Dstore.java @@ -26,6 +26,8 @@ public class Dstore { this.cport = cport; this.timeout = timeout; + DstoreLogger.init(Logger.LoggingType.ON_FILE_AND_TERMINAL, port); + fileFolder = new File(fileFolderName); if(fileFolder.exists() && !fileFolder.isDirectory()) { throw new Exception("Folder name provided exists as a file and not a directory"); @@ -74,14 +76,17 @@ public class Dstore { this.controllerSocket = controllerSocket; controllerIn = new BufferedReader(new InputStreamReader(controllerSocket.getInputStream())); controllerOut = new PrintWriter(controllerSocket.getOutputStream()); - controllerOut.println("JOIN " + port); + String joinMessage = Protocol.JOIN_TOKEN + " " + port; + controllerOut.println(joinMessage); controllerOut.flush(); + messageSent(controllerSocket, joinMessage); new Thread(() -> { while(true) { try { String message = controllerIn.readLine(); if(message != null) { + messageReceived(controllerSocket, message); handleMessage(message.split(" "), controllerSocket); } } @@ -97,8 +102,9 @@ public class Dstore { try { Socket client = server.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); - String[] message = in.readLine().split(" "); - handleMessage(message, client); + String message = in.readLine(); + messageReceived(client, message); + handleMessage(message.split(" "), client); } catch(Exception e) { //Log error @@ -138,8 +144,9 @@ public class Dstore { try { //Send ACK message to client PrintWriter out = new PrintWriter(client.getOutputStream()); - out.println("ACK"); + out.println(Protocol.ACK_TOKEN); out.flush(); + messageSent(client, Protocol.ACK_TOKEN); FileOutputStream writer = new FileOutputStream(new File(fileFolder, filename), false); InputStream reader = client.getInputStream(); @@ -154,8 +161,10 @@ public class Dstore { //Send STORE_ACK message to the Controller synchronized(controllerOut) { - controllerOut.println("STORE_ACK " + filename); + String controllerMessage = Protocol.STORE_ACK_TOKEN + " " + filename; + controllerOut.println(controllerMessage); controllerOut.flush(); + messageSent(controllerSocket, controllerMessage); } if(fileSizes.containsKey(filename)) fileSizes.remove(filename); @@ -174,15 +183,11 @@ public class Dstore { new Thread(() -> { try { //Send the content of the file in fileFolder to the client - PrintWriter out = new PrintWriter(client.getOutputStream()); FileInputStream reader; try { reader = new FileInputStream(new File(fileFolder, filename)); } catch(FileNotFoundException e) { - out.println("ERROR DOES_NOT_EXIST"); - out.flush(); - out.close(); client.close(); return; } @@ -195,7 +200,6 @@ public class Dstore { } reader.close(); - out.close(); contentOut.close(); } catch(IOException e) { @@ -213,20 +217,23 @@ public class Dstore { //Remove the file from fileFolder Path path = new File(fileFolder, filename).toPath(); + String controllerMessage; if(Files.deleteIfExists(path)) { //Send REMOVE_ACK message to client (the controller) synchronized(controllerOut) { - controllerOut.println("REMOVE_ACK " + filename); - controllerOut.flush(); + controllerMessage = Protocol.REMOVE_ACK_TOKEN + " " + filename; + } } else { //Send DOES NOT EXIST error synchronized(controllerOut) { - controllerOut.println("ERROR DOES_NOT_EXIST " + filename); - controllerOut.flush(); + controllerMessage = Protocol.ERROR_FILE_DOES_NOT_EXIST_TOKEN + " " + filename; } } + controllerOut.println(controllerMessage); + controllerOut.flush(); + messageSent(controllerSocket, controllerMessage); } catch(IOException e) { e.printStackTrace(); @@ -301,12 +308,15 @@ public class Dstore { System.out.println("Sending " + filename + " to store " + dstore); Socket socket = new Socket(InetAddress.getLocalHost(), dstore.intValue()); PrintWriter out = new PrintWriter(socket.getOutputStream()); - out.println("STORE " + filename + " " + fileSizes.get(filename)); + String dstoreMessage = Protocol.STORE_TOKEN + " " + filename + " " + fileSizes.get(filename); + out.println(dstoreMessage); out.flush(); + messageSent(socket, dstoreMessage); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); String receivedMessage = in.readLine(); - if(!receivedMessage.equals("ACK")) { + messageReceived(socket, receivedMessage); + if(!receivedMessage.equals(Protocol.ACK_TOKEN)) { //Log error System.out.println("Dstore " + dstore + " should have sent ACK but " + port + " received " + receivedMessage); } @@ -343,11 +353,20 @@ public class Dstore { //Send REBALANCE_COMPLETE message to client (the controller) synchronized(controllerOut) { - controllerOut.println("REBALANCE_COMPLETE"); + controllerOut.println(Protocol.REBALANCE_COMPLETE_TOKEN); controllerOut.flush(); + messageSent(controllerSocket, Protocol.REBALANCE_COMPLETE_TOKEN); } System.out.println("Sent message REBALANCE_COMPLETE"); //TO DO: WAIT FOR RESPONSES BEFORE SENDING REBALANCE_COMPLETE }).start(); } + + protected void messageSent(Socket socket, String message) { + DstoreLogger.getInstance().messageSent(socket, message); + } + + protected void messageReceived(Socket socket, String message) { + DstoreLogger.getInstance().messageReceived(socket, message); + } } diff --git a/DstoreConnection.java b/DstoreConnection.java index 2db4b30bded6f4e39473d6dc1acfcc1a7fce83ab..d402186bcc81d1ab51f7c061ad9aa0fa3a692b9c 100644 --- a/DstoreConnection.java +++ b/DstoreConnection.java @@ -48,7 +48,8 @@ public class DstoreConnection { if(!available) return "ERROR"; writer.println(message); writer.flush(); - System.out.println("Controller sent " + message + " to port " + port); + //System.out.println("Controller sent " + message + " to port " + port); + ControllerLogger.getInstance().messageSent(socket, message); return localReceive(expectedMessage); } catch(NullPointerException e) { @@ -158,6 +159,7 @@ public class DstoreConnection { available = false; throw disconnectException; } + ControllerLogger.getInstance().messageReceived(socket, message); if(expectedMessage != null && !expectedMessage.equals(message.split(" ")[0])) { queue.add(message); if(queue.size() > MAX_QUEUE_SIZE) queue.remove(0); @@ -165,7 +167,7 @@ public class DstoreConnection { } } while(message == null); - System.out.println("Controller received " + message + " from port " + port); + //System.out.println("Controller received " + message + " from port " + port); returnMessage = message; } catch(IOException e) { diff --git a/Execute.sh b/Execute.sh index 1090c62a9162734b753ea5be6a6968a9c1a47193..b6719668a1e1f998fc080203f9632646de2ccb3d 100755 --- a/Execute.sh +++ b/Execute.sh @@ -1,12 +1,12 @@ #!/bin/bash -java Controller 8080 $1 $3 $4 & +java -cp .:loggers Controller 8080 $1 $3 $4 & echo $! for((i=1; i<=$2; i++)) do sleep 0.2 n=$((8080+$i)) echo $n s="store$i" - java Dstore $n 8080 $3 $s & + java -cp .:loggers Dstore $n 8080 $3 $s & echo $! done sleep 2 diff --git a/Protocol.java b/Protocol.java new file mode 100644 index 0000000000000000000000000000000000000000..25181131b0d0226678818b39344f787b47cbc66e --- /dev/null +++ b/Protocol.java @@ -0,0 +1,30 @@ + +public class Protocol { + + // messages from Clients + public final static String LIST_TOKEN = "LIST"; // also from Controller and Dstores + public final static String STORE_TOKEN = "STORE"; // also from Dstores + public final static String LOAD_TOKEN = "LOAD"; + public final static String LOAD_DATA_TOKEN = "LOAD_DATA"; + public final static String RELOAD_TOKEN = "RELOAD"; + public final static String REMOVE_TOKEN = "REMOVE"; // also from Controller + + // messages from Controller + public final static String STORE_TO_TOKEN = "STORE_TO"; + public final static String STORE_COMPLETE_TOKEN = "STORE_COMPLETE"; + public final static String LOAD_FROM_TOKEN = "LOAD_FROM"; + public final static String REMOVE_COMPLETE_TOKEN = "REMOVE_COMPLETE"; + public final static String REBALANCE_TOKEN = "REBALANCE"; + public final static String ERROR_FILE_DOES_NOT_EXIST_TOKEN = "ERROR_FILE_DOES_NOT_EXIST"; // also from Dstores + public final static String ERROR_FILE_ALREADY_EXISTS_TOKEN = "ERROR_FILE_ALREADY_EXISTS"; + public final static String ERROR_NOT_ENOUGH_DSTORES_TOKEN = "ERROR_NOT_ENOUGH_DSTORES"; + public final static String ERROR_LOAD_TOKEN = "ERROR_LOAD"; + + // messages from Dstores + public final static String ACK_TOKEN = "ACK"; + public final static String STORE_ACK_TOKEN = "STORE_ACK"; + public final static String REMOVE_ACK_TOKEN = "REMOVE_ACK"; + public final static String JOIN_TOKEN = "JOIN"; + public final static String REBALANCE_STORE_TOKEN = "REBALANCE_STORE"; + public final static String REBALANCE_COMPLETE_TOKEN = "REBALANCE_COMPLETE"; +} diff --git a/RebalanceLock.java b/RebalanceLock.java new file mode 100644 index 0000000000000000000000000000000000000000..8f25a524fdf9781c9310a1d09320caf383ddcd49 --- /dev/null +++ b/RebalanceLock.java @@ -0,0 +1,64 @@ +import java.util.concurrent.*; + +/* +Rebalance operations and client requests cannot occur simultaneously +This class queues requests while a rebalance takes place and makes the thread calling a rebalance wait until all running requests have been served +*/ +public class RebalanceLock { + protected int processes; + protected int rebalancePeriod; + protected boolean highPriorityWait; + protected CountDownLatch periodBlock; + protected Object blockLock; + + public RebalanceLock(int rebalancePeriod) { + processes = 0; + this.rebalancePeriod = rebalancePeriod; + periodBlock = new CountDownLatch(1); + blockLock = new Object(); + } + + public synchronized void addProcess() throws InterruptedException { + while(highPriorityWait) { + this.wait(); + } + + processes ++; + } + + public synchronized void removeProcess() { + processes --; + if(processes == 0) this.notifyAll(); + } + + public void waitForFinish() { + while(processes > 0) { + highPriorityWait = true; + try { + this.wait(); + } + catch(InterruptedException e) {e.printStackTrace();} + } + highPriorityWait = false; + } + + public void queueRebalance() { + synchronized(blockLock) { + periodBlock.countDown(); + } + } + + public boolean waitToRebalance() { + try { + boolean dstoreJoined = periodBlock.await(rebalancePeriod, TimeUnit.MILLISECONDS); + if(dstoreJoined) { + synchronized(blockLock) { + periodBlock = new CountDownLatch(1); + } + } + return dstoreJoined; + } + catch(InterruptedException e) {e.printStackTrace();} + return true; + } +} diff --git a/loggers/ControllerLogger.java b/loggers/ControllerLogger.java new file mode 100644 index 0000000000000000000000000000000000000000..30f0f8f76ca72bf2f3344c2540b09ecd526727b1 --- /dev/null +++ b/loggers/ControllerLogger.java @@ -0,0 +1,36 @@ +import java.io.IOException; +import java.net.Socket; + +public class ControllerLogger extends Logger { + + private static final String LOG_FILE_SUFFIX = "controller"; + + private static ControllerLogger instance = null; + + public static void init(LoggingType loggingType) throws IOException { + if (instance == null) + instance = new ControllerLogger(loggingType); + else + throw new IOException("ControllerLogger already initialised"); + } + + public static ControllerLogger getInstance() { + if (instance == null) + throw new RuntimeException("ControllerLogger has not been initialised yet"); + return instance; + } + + protected ControllerLogger(LoggingType loggingType) throws IOException { + super(loggingType); + } + + @Override + protected String getLogFileSuffix() { + return LOG_FILE_SUFFIX; + } + + public void dstoreJoined(Socket socket, int dstorePort) { + log("[New Dstore " + dstorePort + " " + socket.getLocalPort() + "<-" + socket.getPort() + "]"); + } + +} diff --git a/loggers/DstoreLogger.java b/loggers/DstoreLogger.java new file mode 100644 index 0000000000000000000000000000000000000000..24982ce092cb7e790305a8d5961e1dfec92250ca --- /dev/null +++ b/loggers/DstoreLogger.java @@ -0,0 +1,34 @@ +import java.io.IOException; + +public class DstoreLogger extends Logger { + +private static final String LOG_FILE_SUFFIX = "dstore"; + + private static DstoreLogger instance = null; + + private final String logFileSuffix; + + public static void init(LoggingType loggingType, int port) throws IOException { + if (instance == null) + instance = new DstoreLogger(loggingType, port); + else + throw new IOException("DstoreLogger already initialised"); + } + + public static DstoreLogger getInstance() { + if (instance == null) + throw new RuntimeException("DstoreLogger has not been initialised yet"); + return instance; + } + + protected DstoreLogger(LoggingType loggingType, int port) throws IOException { + super(loggingType); + logFileSuffix = LOG_FILE_SUFFIX + "_" + port; + } + + @Override + protected String getLogFileSuffix() { + return logFileSuffix; + } + +} diff --git a/loggers/Logger.java b/loggers/Logger.java new file mode 100644 index 0000000000000000000000000000000000000000..14f3bf8b9fd6e1f35be840558b71146128a3fb31 --- /dev/null +++ b/loggers/Logger.java @@ -0,0 +1,52 @@ +import java.io.IOException; +import java.io.PrintStream; +import java.net.Socket; + +public abstract class Logger { + + public enum LoggingType { + NO_LOG, // no log at all + ON_TERMINAL_ONLY, // log to System.out only + ON_FILE_ONLY, // log to file only + ON_FILE_AND_TERMINAL // log to both System.out and file + } + + protected final LoggingType loggingType; + protected PrintStream ps; + + protected Logger(LoggingType loggingType) { + this.loggingType = loggingType; + } + + protected abstract String getLogFileSuffix(); + + protected synchronized PrintStream getPrintStream() throws IOException { + if (ps == null) + ps = new PrintStream(getLogFileSuffix() + "_" + System.currentTimeMillis() + ".log"); + return ps; + } + + protected boolean logToFile() { + return loggingType == LoggingType.ON_FILE_ONLY || loggingType == LoggingType.ON_FILE_AND_TERMINAL; + } + + protected boolean logToTerminal() { + return loggingType == LoggingType.ON_TERMINAL_ONLY || loggingType == LoggingType.ON_FILE_AND_TERMINAL; + } + + protected void log(String message) { + if (logToFile()) + try { getPrintStream().println(message); } catch(Exception e) { e.printStackTrace(); } + if (logToTerminal()) + System.out.println(message); + } + + public void messageSent(Socket socket, String message) { + log("[" + socket.getLocalPort() + "->" + socket.getPort() + "] " + message); + } + + public void messageReceived(Socket socket, String message) { + log("[" + socket.getLocalPort() + "<-" + socket.getPort() + "] " + message); + } + +} diff --git a/to_store/Look Away.mp3 b/to_store/Look Away.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..11fe75bfbce62c4f1300d06f12d9a15c5e06722c Binary files /dev/null and b/to_store/Look Away.mp3 differ