diff --git a/src/clientP2P/ClientInterface.java b/src/clientP2P/ClientInterface.java new file mode 100644 index 0000000..2759e01 --- /dev/null +++ b/src/clientP2P/ClientInterface.java @@ -0,0 +1,41 @@ +package clientP2P; +import clientP2P.ClientManagement; +import tools.Logger; +import tools.LogLevel; + +/** Implementation of P2P-JAVA-PROJECT CLIENT interface + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public abstract class ClientInterface implements Runnable { + protected ClientManagement clientManagement; + private Logger logger; + + /** Constructor with clientManagement and logger. + * @param clientManagement ClientManagement used + * @param logger Logger used + */ + public ClientInterface(ClientManagement clientManagement, Logger logger) { + this.clientManagement = clientManagement; + this.logger = logger; + } + + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging + */ + protected void writeLog(String text, LogLevel logLevel) { + logger.write(text, logLevel); + } + + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging + */ + protected void writeLog(Exception e, LogLevel logLevel) { + logger.write(e, logLevel); + } + +} diff --git a/src/clientP2P/ClientInterfaceCLI.java b/src/clientP2P/ClientInterfaceCLI.java new file mode 100644 index 0000000..842c50e --- /dev/null +++ b/src/clientP2P/ClientInterfaceCLI.java @@ -0,0 +1,139 @@ +package clientP2P; +import clientP2P.ClientInterface; +import clientP2P.ClientManagement; +import tools.LogLevel; +import tools.Logger; +import java.util.Scanner; +import localException.ProtocolError; +import localException.InternalError; +import localException.ProtocolError; +import localException.SizeError; +import localException.TransmissionError; +import localException.VersionError; +import localException.SocketClosed; +import remoteException.EmptyFile; +import remoteException.EmptyDirectory; +import remoteException.InternalRemoteError; +import remoteException.NotFound; +import remoteException.ProtocolRemoteError; +import remoteException.VersionRemoteError; +import remoteException.NotATracker; +import remoteException.UnknownHost; +import java.io.IOException; +import java.net.UnknownHostException; +import java.net.SocketException; + +/** Implementation of P2P-JAVA-PROJECT CLIENT interface for CLI + * @author Louis Royer + * @author Flavien Haas + * @author JS Auge + * @version 1.0 + */ +public class ClientInterfaceCLI extends ClientInterface { + private Scanner scanner; + + /** Constructor with clientManagement, logger and scanner. + * @param clientManagement ClientManagement used + * @param logger Logger used + * @param scanner Scanner used to read input + */ + public ClientInterfaceCLI(ClientManagement clientManagement, Logger logger, Scanner scanner) { + super(clientManagement, logger); + this.scanner = scanner; + } + + /** Implementation of Runnable + */ + public void run() { + boolean isRunning = true; + while (isRunning) { + try { + int i = 1; + String[] list = clientManagement.listDirectory(); + System.out.println("Files present on the server:"); + System.out.println("R: Refresh file list"); + System.out.println("0: Exit the program"); + for(String listItem: list) { + System.out.println(i + ": " + listItem); + i++; + } + System.out.println("Type the number associated with the file to download:"); + String f = scanner.nextLine(); + if (f.equals("0")) { + isRunning = false; + } else if (f.equals("R") || f.equals("r")) { + writeLog("File list refresh.", LogLevel.Info); + } else { + try { + int j = Integer.parseInt(f); + if (j <= list.length) { + j--; + clientManagement.download(list[j]); + writeLog("File " + f + " sucessfully downloaded", LogLevel.Info); + } else { + writeLog("File " + f + " unsucessfully downloaded, wrong number", LogLevel.Error); + } + } catch (NumberFormatException e) { + writeLog("File " + f + " unsucessfully downloaded, wrong number", LogLevel.Error); + } + } + } catch (EmptyDirectory e) { + writeLog("Server has no file in directory", LogLevel.Error); + } catch (InternalError e) { + writeLog("Client internal error", LogLevel.Error); + } catch (UnknownHostException e) { + writeLog("Server host is unknown", LogLevel.Error); + } catch (IOException e) { + writeLog("Request cannot be send or response cannot be received", LogLevel.Error); + } catch (TransmissionError e) { + writeLog("Message received is too big", LogLevel.Error); + } catch (ProtocolError e) { + writeLog("Cannot decode server’s response", LogLevel.Error); + } catch (VersionError e) { + writeLog("Server’s response use bad version of the protocol", LogLevel.Error); + } catch (SizeError e) { + writeLog("Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error); + } catch (InternalRemoteError e) { + writeLog("Server internal error", LogLevel.Error); + } catch (ProtocolRemoteError e) { + writeLog("Server cannot decode client’s request", LogLevel.Error); + } catch (VersionRemoteError e) { + writeLog("Server cannot decode this version of the protocol", LogLevel.Error); + } catch (NotFound e) { + writeLog("Server has not this file in directory", LogLevel.Error); + } catch (EmptyFile e) { + writeLog("File is empty", LogLevel.Error); + } + } + writeLog("Exiting client", LogLevel.Info); + } + + /** Initialization of hostList with retry in failure + * @return true if successfully initialized + */ + private boolean initHostList() { + boolean contacted = false; + boolean firstLoop = true; + boolean stop = false; + while (!contacted && !stop) { + try { + if (!firstLoop) { + writeLog("Cannot contact tracker. Try again [Y/n] ?", LogLevel.Error); + String tryAgain = scanner.nextLine(); + if (tryAgain.equals("n") || tryAgain.equals("N")) { + stop = true; + } + } + firstLoop = false; + clientManagement.initHostList(); + contacted = true; + } catch (SocketException e) { + } catch (UnknownHostException e) { + } catch (IOException e) { + } catch (Exception e) { + return false; + } + } + return !stop; + } +} diff --git a/src/clientP2P/ClientManagement.java b/src/clientP2P/ClientManagement.java index 2cb4455..f928506 100644 --- a/src/clientP2P/ClientManagement.java +++ b/src/clientP2P/ClientManagement.java @@ -1,8 +1,8 @@ package clientP2P; import java.util.Arrays; -import java.util.Scanner; import java.util.List; +import java.util.ArrayList; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; @@ -31,6 +31,8 @@ import remoteException.ProtocolRemoteError; import remoteException.VersionRemoteError; import remoteException.NotATracker; import remoteException.UnknownHost; +import exception.RemoteException; +import exception.LocalException; import tools.ServeErrors; import tools.HostItem; import tools.Logger; @@ -43,14 +45,13 @@ import java.net.SocketException; * @author JS Auge * @version 1.0 */ -public abstract class ClientManagement extends ServeErrors implements Runnable { +public abstract class ClientManagement extends ServeErrors { protected String baseDirectory; protected String partsSubdir; - protected List hostList; + protected List hostList = new ArrayList<>(); protected HostItem tracker; protected HostItem client; protected Logger logger; - protected Scanner scanner; protected ClientDownload downLoader; /** Constructor with baseDirectory, tracker, partsSubdir, logger, and scanner parameters. @@ -58,23 +59,14 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { * @param tracker Tracker hostItem * @param partsSubdir subdirectory to store file parts * @param logger Loggger - * @param scanner Scanner used to read input * @param client HostItem of the application */ - public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) { - this.scanner = scanner; + public ClientManagement(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, HostItem client) { this.baseDirectory = baseDirectory; this.tracker = tracker; this.partsSubdir = partsSubdir; this.logger = logger; this.client = client; - try { - initHostList(); - } catch (InternalError e) { - System.exit(-1); - } catch (ProtocolError e) { - System.exit(-2); - } } /** Getter for tracker socket @@ -93,33 +85,14 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { /** Initialize hostList from tracker * @throws ProtocolError * @throws InternalError + * @throws SocketException + * @throws UnknownHostException + * @throws IOException */ - private void initHostList() throws ProtocolError, InternalError { + public void initHostList() throws ProtocolError, InternalError, SocketException, UnknownHostException, IOException { ProtocolP2PPacket d = createProtocolP2PPacket(new DiscoverRequest(null)); try { - boolean contacted = false; - boolean firstLoop = true; - boolean stop = false; - while (!contacted && !stop) { - try { - if (!firstLoop) { - writeLog("Cannot contact tracker. Try again [Y/n] ?", LogLevel.Error); - String tryAgain = scanner.nextLine(); - if (tryAgain.equals("n") || tryAgain.equals("N")) { - stop = true; - } - } - firstLoop = false; - d.sendRequest(getTrackerSocket()); - contacted = true; - } catch (SocketException e) { - } catch (UnknownHostException e) { - } catch (IOException e) { - } - } - if (stop) { - System.exit(3); - } + d.sendRequest(getTrackerSocket()); Payload p = d.receiveResponse().getPayload(); assert p instanceof DiscoverResponse : "This payload must be instance of Filelist"; if (!(p instanceof DiscoverResponse)) { @@ -131,10 +104,10 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { } catch (SocketClosed e) { writeLog("listDirectory : SocketClosed", LogLevel.Error); throw new ProtocolError(); - } catch (NotATracker e) { + } catch (LocalException e) { writeLog(e, LogLevel.Error); throw new ProtocolError(); - } catch (Exception e) { + } catch (RemoteException e) { writeLog(e, LogLevel.Error); throw new ProtocolError(); } @@ -144,7 +117,7 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { * @param filename * @return hashsum */ - protected byte[] computeHashsum(String filename, HashAlgorithm h) { + private byte[] computeHashsum(String filename, HashAlgorithm h) { try { MessageDigest md = MessageDigest.getInstance(HashAlgorithm.SHA512.getName()); return md.digest(Files.readAllBytes(Paths.get(baseDirectory + filename))); @@ -181,7 +154,7 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { * @throws ProtocolRemoteError * @throws VersionRemoteError */ - protected String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { + public String[] listDirectory() throws EmptyDirectory, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { if (hostList.size() == 0) { return new String[0]; } @@ -234,7 +207,7 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { * @throws VersionRemoteError * @throws EmptyFile */ - private void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { + public void download(String filename) throws EmptyFile, NotFound, InternalError, UnknownHostException, IOException, TransmissionError, ProtocolError, VersionError, SizeError, InternalRemoteError, ProtocolRemoteError, VersionRemoteError { initDownloader(filename); Thread t = new Thread(downLoader); t.start(); @@ -268,69 +241,15 @@ public abstract class ClientManagement extends ServeErrors implements Runnable { } } - /** Implementation of Runnable + /** Implementation of writeLog + * @param text Text to log + * @param logLevel level of logging */ - public void run() { - boolean isRunning = true; - while (isRunning) { - try { - int i = 1; - String[] list = listDirectory(); - System.out.println("Files present on the server:"); - System.out.println("R: Refresh file list"); - System.out.println("0: Exit the program"); - for(String listItem: list) { - System.out.println(i + ": " + listItem); - i++; - } - System.out.println("Type the number associated with the file to download:"); - String f = scanner.nextLine(); - if (f.equals("0")) { - isRunning = false; - } else if (f.equals("R") || f.equals("r")) { - writeLog("File list refresh.", LogLevel.Info); - } else { - try { - int j = Integer.parseInt(f); - if (j <= list.length) { - j--; - download(list[j]); - writeLog("File " + f + " sucessfully downloaded", LogLevel.Info); - } else { - writeLog("File " + f + " unsucessfully downloaded, wrong number", LogLevel.Error); - } - } catch (NumberFormatException e) { - writeLog("File " + f + " unsucessfully downloaded, wrong number", LogLevel.Error); - } - } - } catch (EmptyDirectory e) { - writeLog("Server has no file in directory", LogLevel.Error); - } catch (InternalError e) { - writeLog("Client internal error", LogLevel.Error); - } catch (UnknownHostException e) { - writeLog("Server host is unknown", LogLevel.Error); - } catch (IOException e) { - writeLog("Request cannot be send or response cannot be received", LogLevel.Error); - } catch (TransmissionError e) { - writeLog("Message received is too big", LogLevel.Error); - } catch (ProtocolError e) { - writeLog("Cannot decode server’s response", LogLevel.Error); - } catch (VersionError e) { - writeLog("Server’s response use bad version of the protocol", LogLevel.Error); - } catch (SizeError e) { - writeLog("Cannot handle this packets because of internal representation limitations of numbers on the client", LogLevel.Error); - } catch (InternalRemoteError e) { - writeLog("Server internal error", LogLevel.Error); - } catch (ProtocolRemoteError e) { - writeLog("Server cannot decode client’s request", LogLevel.Error); - } catch (VersionRemoteError e) { - writeLog("Server cannot decode this version of the protocol", LogLevel.Error); - } catch (NotFound e) { - writeLog("Server has not this file in directory", LogLevel.Error); - } catch (EmptyFile e) { - writeLog("File is empty", LogLevel.Error); - } - } - writeLog("Exiting client", LogLevel.Info); - } + protected abstract void writeLog(String text, LogLevel logLevel); + + /** Implementation of writeLog + * @param e exception to log + * @param logLevel level of logging + */ + protected abstract void writeLog(Exception e, LogLevel logLevel); } diff --git a/src/clientP2P/ClientManagementTCP.java b/src/clientP2P/ClientManagementTCP.java index 5372ec8..e67bd1b 100644 --- a/src/clientP2P/ClientManagementTCP.java +++ b/src/clientP2P/ClientManagementTCP.java @@ -26,11 +26,10 @@ public class ClientManagementTCP extends ClientManagement { * @param tracker Tracker hostItem * @param partsSubdir subdirectory to store file parts * @param logger Loggger - * @param scanner Scanner used to read input * @param client HostItem of the application */ - public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) { - super(baseDirectory, tracker, partsSubdir, logger, scanner, client); + public ClientManagementTCP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, HostItem client) { + super(baseDirectory, tracker, partsSubdir, logger, client); } /** Initialize downloader diff --git a/src/clientP2P/ClientManagementUDP.java b/src/clientP2P/ClientManagementUDP.java index d700587..543c317 100644 --- a/src/clientP2P/ClientManagementUDP.java +++ b/src/clientP2P/ClientManagementUDP.java @@ -25,11 +25,10 @@ public class ClientManagementUDP extends ClientManagement { * @param tracker tracker HostItem * @param partsSubdir subdirectory to store file parts * @param logger Loggger - * @param scanner Scanner used to read input * @param client HostItem of the application */ - public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, Scanner scanner, HostItem client) { - super(baseDirectory, tracker, partsSubdir, logger, scanner, client); + public ClientManagementUDP(String baseDirectory, HostItem tracker, String partsSubdir, Logger logger, HostItem client) { + super(baseDirectory, tracker, partsSubdir, logger, client); } /** Initialize downloader diff --git a/src/clientP2P/ClientP2P.java b/src/clientP2P/ClientP2P.java index 0129169..330b2f4 100644 --- a/src/clientP2P/ClientP2P.java +++ b/src/clientP2P/ClientP2P.java @@ -5,6 +5,7 @@ import java.util.List; import clientP2P.ClientManagementUDP; import clientP2P.ClientManagementTCP; import serverP2P.ServerManagementUDP; +import clientP2P.ClientInterfaceCLI; import serverP2P.ServerManagementTCP; import tools.Logger; import tools.LogLevel; @@ -166,16 +167,16 @@ public class ClientP2P { case "upd": // to avoid users typos case "2" : System.out.println("Starting with UDP"); - ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner, c.server); - tclient = new Thread(cmudp); + ClientManagementUDP cmudp = new ClientManagementUDP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.server); + tclient = new Thread(new ClientInterfaceCLI(cmudp, c.loggerClient, c.scanner)); break; case "TCP": case "tcp": case "1": default: System.out.println("Starting with TCP"); - ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.scanner, c.server); - tclient = new Thread(cmtcp); + ClientManagementTCP cmtcp = new ClientManagementTCP(c.directories.getDataHomeDirectory(), c.tracker, c.directories.getDataHomeDirectory() + c.partsDir, c.loggerClient, c.server); + tclient = new Thread(new ClientInterfaceCLI(cmtcp, c.loggerClient, c.scanner)); break; } tclient.setName("client P2P-JAVA-PROJECT"); diff --git a/src/serverP2P/FileWatcherTCP.java b/src/serverP2P/FileWatcherTCP.java index 7aa9df7..ce02e79 100644 --- a/src/serverP2P/FileWatcherTCP.java +++ b/src/serverP2P/FileWatcherTCP.java @@ -50,7 +50,7 @@ public class FileWatcherTCP extends FileWatcher { */ protected void registerTracker() { try { - writeLog("Trying to into tracker", LogLevel.Info); + writeLog("Trying to register into tracker", LogLevel.Info); ProtocolP2PPacket p = (ProtocolP2PPacket)new ProtocolP2PPacketTCP(new Register(server)); p.sendRequest((Object)tracker.tryGetTCPSocket()); writeLog("Register request sent.", LogLevel.Debug); diff --git a/src/serverP2P/ServerManagement.java b/src/serverP2P/ServerManagement.java index 5271c6f..787ea2d 100644 --- a/src/serverP2P/ServerManagement.java +++ b/src/serverP2P/ServerManagement.java @@ -26,6 +26,8 @@ import java.util.Map; import java.util.HashMap; import java.util.Random; import java.io.IOException; +import java.net.UnknownHostException; +import java.net.SocketException; import exception.LocalException; import localException.InternalError; import remoteException.UnknownHost; @@ -253,8 +255,13 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { /** Getter for tracker socket + * @return Tracker's socket + * @throws SocketException + * @throws UnknownHostException + * @throws IOException */ - protected abstract Object getTrackerSocket(); + protected abstract Object getTrackerSocket() throws SocketException, UnknownHostException, IOException; + /** Send unregister request to tracker */ @@ -263,7 +270,13 @@ public abstract class ServerManagement extends ServeErrors implements Runnable { try { writeLog("Unregistering from tracker", LogLevel.Info); createProtocolP2PPacket(new Unregister(server)).sendRequest(getTrackerSocket()); - } catch (Exception e) { + } catch (SocketException e) { + writeLog("Cannot unregister from tracker", LogLevel.Error); + } catch (UnknownHostException e) { + writeLog("Cannot unregister from tracker", LogLevel.Error); + } catch (IOException e) { + writeLog("Cannot unregister from tracker", LogLevel.Error); + } catch (Exception e) { writeLog("Cannot unregister from tracker", LogLevel.Error); writeLog(e, LogLevel.Error); } diff --git a/src/serverP2P/ServerManagementTCP.java b/src/serverP2P/ServerManagementTCP.java index c8e4930..55f81e0 100644 --- a/src/serverP2P/ServerManagementTCP.java +++ b/src/serverP2P/ServerManagementTCP.java @@ -30,6 +30,7 @@ import tools.LogLevel; import tools.HostItem; import java.util.HashMap; import java.util.Map; +import java.net.UnknownHostException; import protocolP2P.HashAlgorithm; import protocolP2P.HashRequest; import protocolP2P.HashResponse; @@ -169,11 +170,15 @@ public class ServerManagementTCP extends ServerManagement { /** Getter for tracker socket * @return Tracker's socket + * @throws SocketException + * @throws UnknownHostException + * @throws IOException */ - protected Object getTrackerSocket() { - return (Object)tracker.getTCPSocket(); + protected Object getTrackerSocket() throws SocketException, UnknownHostException, IOException { + return (Object)tracker.tryGetTCPSocket(); } + /** Closes socket */ protected void closeSocket() { try { diff --git a/src/serverP2P/ServerManagementUDP.java b/src/serverP2P/ServerManagementUDP.java index 7471241..c9c3d7b 100644 --- a/src/serverP2P/ServerManagementUDP.java +++ b/src/serverP2P/ServerManagementUDP.java @@ -122,12 +122,16 @@ public class ServerManagementUDP extends ServerManagement { } /** Getter for tracker socket - * @return Tracker's socket + * @return Tracker's socket + * @throws SocketException + * @throws UnknownHostException + * @throws IOException */ - protected Object getTrackerSocket() { - return (Object)tracker.getUDPSocket(); + protected Object getTrackerSocket() throws SocketException, UnknownHostException, IOException { + return (Object)tracker.tryGetUDPSocket(); } + /** Closes socket */ protected void closeSocket() { socket.close(); diff --git a/src/tools/HostItem.java b/src/tools/HostItem.java index 9808fed..ec723fa 100644 --- a/src/tools/HostItem.java +++ b/src/tools/HostItem.java @@ -35,13 +35,16 @@ public class HostItem { try { return tryGetTCPSocket(); } catch (SocketException e) { - System.err.println("getTCPSocket error: No TCP socket available."); + System.err.println("getTCPSocket error: No TCP socket available (" + this +")."); + e.printStackTrace(); System.exit(-1); } catch (UnknownHostException e) { System.err.println("getTCPSocket error: Unknown host (" + this + ")."); + e.printStackTrace(); System.exit(-1); } catch (IOException e) { System.err.println("getTCPSocket error: Cannot create TCP socket (" + this + ")."); + e.printStackTrace(); System.exit(-1); } return null; // java compiler is stupid and doesn't know about System.exit @@ -80,7 +83,7 @@ public class HostItem { try { return tryGetUDPSocket(); } catch (SocketException e) { - System.err.println("getUDPSocket error: No UDP socket available." ); + System.err.println("getUDPSocket error: No UDP socket available ( " + this + ")." ); System.exit(-1); } catch (UnknownHostException e) { System.err.println("getUDPSocket error: Unknown host (" + this + ")."); diff --git a/src/tools/Logger.java b/src/tools/Logger.java index 16dda46..3f3d2ae 100644 --- a/src/tools/Logger.java +++ b/src/tools/Logger.java @@ -101,6 +101,15 @@ public class Logger { } } + /** Appends log to filelog and print to stderr. + * @param e Exception to log + * @param logLevel Type of log + */ + public void write(Exception e, LogLevel logLevel) { + write(e.toString(), logLevel); + e.printStackTrace(); + } + /** Appends log to filelog and print to stderr. * Adds [TCP] in log line. * @param text Text to log @@ -112,7 +121,7 @@ public class Logger { /** Appends log to filelog and print to stderr. * Adds [TCP] in log line. - * @param text Text to log + * @param e Exception to log * @param logLevel Type of log */ public void writeTCP(Exception e, LogLevel logLevel) { @@ -131,7 +140,7 @@ public class Logger { /** Appends log to filelog and print to stderr. * Adds [UDP] in log line. - * @param text Text to log + * @param e Excetpino to log * @param logLevel Type of log */ public void writeUDP(Exception e, LogLevel logLevel) {