diff --git a/app/src/main/java/lightcontainer/App.java b/app/src/main/java/lightcontainer/App.java index 44860f4..58584a3 100644 --- a/app/src/main/java/lightcontainer/App.java +++ b/app/src/main/java/lightcontainer/App.java @@ -10,8 +10,7 @@ import lightcontainer.protocol.rules.reader.FilelistRule; import lightcontainer.protocol.rules.reader.HelloRule; import lightcontainer.protocol.rules.reader.SavefileRule; import lightcontainer.protocol.rules.reader.SigninRule; -import lightcontainer.protocol.rules.writer.SignErrorRule; -import lightcontainer.protocol.rules.writer.SignOkRule; +import lightcontainer.protocol.rules.writer.*; import lightcontainer.repository.ClientHandlerRepository; import lightcontainer.repository.FileFrontEnd; import lightcontainer.repository.ProtocolRepositoryImpl; @@ -62,12 +61,15 @@ public class App { ProtocolRepository protocolRep = new ProtocolRepositoryImpl(); protocolRep.addReader(new HelloRule()); - protocolRep.addReader(new SigninRule()); - protocolRep.addReader(new FilelistRule()); - protocolRep.addReader(new SavefileRule()); + protocolRep.addReader(new SigninRule(protocolRep)); + protocolRep.addReader(new FilelistRule(protocolRep)); + protocolRep.addReader(new SavefileRule(protocolRep)); protocolRep.addWriter(new SignOkRule()); protocolRep.addWriter(new SignErrorRule()); + protocolRep.addWriter(new FilesRule()); + protocolRep.addWriter(new SaveFileOkRule()); + protocolRep.addWriter(new SaveFileErrorRule()); new UnicastServerListener(clientRep, protocolRep, UNICAST_PORT); new MulticastServerListener(storeRep, protocolRep, MULTICAST_IP, MULTICAST_PORT); diff --git a/app/src/main/java/lightcontainer/domains/Task.java b/app/src/main/java/lightcontainer/domains/Task.java index 9ff6369..556b339 100644 --- a/app/src/main/java/lightcontainer/domains/Task.java +++ b/app/src/main/java/lightcontainer/domains/Task.java @@ -5,7 +5,6 @@ import lightcontainer.enumerations.TaskType; public class Task { // Variables - private TaskType type; // TODO : Supprimer car innutile ? private TaskStatus status; private String command; private String client; @@ -21,4 +20,21 @@ public class Task { Task task = new Task(TaskStatus.PENDING, command, client); return task; } + + /** + * Permet de savoir si la réponse est destinée au client + * @param storeDomain Nom du store back end fournissant la réponse. + * @return TRUE si le client doit recevoir cette réponse. + */ + public boolean isResponseOfClient(String storeDomain) { + return (this.storeDomain == storeDomain && status == TaskStatus.PENDING); + } + + /** + * Permet de récupérer le login du client associé à la tâche + * @return Login du client + */ + public String getClient() { + return client; + } } diff --git a/app/src/main/java/lightcontainer/domains/client/ClientHandler.java b/app/src/main/java/lightcontainer/domains/client/ClientHandler.java index 773ecc3..b75ade2 100644 --- a/app/src/main/java/lightcontainer/domains/client/ClientHandler.java +++ b/app/src/main/java/lightcontainer/domains/client/ClientHandler.java @@ -41,6 +41,7 @@ public class ClientHandler implements Runnable, AutoCloseable { private BufferedReader reader; private PrintWriter writer; + private ProtocolWriter.ProtocolResult response; // Constructor public ClientHandler(Socket client, ClientHandlerFFE ffe, ProtocolRepository protocolRep) { @@ -86,20 +87,27 @@ public class ClientHandler implements Runnable, AutoCloseable { while (this.client_run) { try { String command = this.reader.readLine(); - // TODO gestion de la réception de commandes, fichier, ... if (command != null) System.out.println("Client: " + command); ProtocolReader.ProtocolResult ruleResult = protocolRep.executeReader(command + "\r\n"); if (isConnected()) { + ProtocolWriter.ProtocolResult writerCommand = ruleResult.getResultCommand(); ruleResult.read( this.client.getInputStream() ); if (ruleResult.getReceiver() == ProtocolReader.ResultCmdReceiver.STOREBACKEND) { - fileFrontEnd.newCommand(command, ruleResult.getResultCommand()); // Envoie dans la file de tâche FileFrontEnd en attente d'un traitement d'un StorBackEnd + fileFrontEnd.newCommand(command, writerCommand.getCommand()); // Envoie dans la file de tâche FileFrontEnd en attente d'un traitement d'un StorBackEnd + + // Attend la fin de la réalisation de la tâche + waitTaskResponse(); + + writer.write(response.getCommand()); // Renvoye au client + writer.flush(); + response.write(this.client.getOutputStream()); // Ecrit au client si nécessaire } else { - writer.write(ruleResult.getResultCommand()); // Renvoye au client + writer.write(writerCommand.getCommand()); // Renvoye au client writer.flush(); } @@ -107,6 +115,25 @@ public class ClientHandler implements Runnable, AutoCloseable { authentication(ruleResult); } } catch (IOException ignore) { } + + } + } + + /** + * Permet au Client d'attendre la fin de la réalisation de sa tâche + */ + private void waitTaskResponse() { + synchronized (this) { + try { + this.wait(); + } catch (InterruptedException e) { e.printStackTrace(); } + } + } + + public void respond(ProtocolWriter.ProtocolResult response) { + this.response = response; + synchronized (this) { + this.notify(); } } diff --git a/app/src/main/java/lightcontainer/domains/client/StoreProcessor.java b/app/src/main/java/lightcontainer/domains/client/StoreProcessor.java index 7a2321f..450eb35 100644 --- a/app/src/main/java/lightcontainer/domains/client/StoreProcessor.java +++ b/app/src/main/java/lightcontainer/domains/client/StoreProcessor.java @@ -79,7 +79,7 @@ public class StoreProcessor extends Thread implements AutoCloseable { this.client_run = true; while (this.client_run) { try { - alertAvalaible(); + waitAction(); // Request ProtocolWriter.ProtocolResult requestResult = protocolRep.executeWriter(this.currentCommand); @@ -92,8 +92,11 @@ public class StoreProcessor extends Thread implements AutoCloseable { if (responseCommand != null) System.out.println("StoreBackEnd: " + responseCommand); ProtocolReader.ProtocolResult responseResult = protocolRep.executeReader(responseCommand); + responseResult.read(this.store.getInputStream()); System.out.println("StoreBackEnd response to client: " + responseResult.getResultCommand()); + alertAvalaible(responseResult.getResultCommand()); + // TODO : Faire en sorte que getResultCommand retourne un ProtocolWriter } catch (IOException ignore) { } } @@ -113,12 +116,20 @@ public class StoreProcessor extends Thread implements AutoCloseable { /** * Permet de déclarer le StoreBackEnd disponible */ - private void alertAvalaible() { + private void alertAvalaible(ProtocolWriter.ProtocolResult responseCommand) { synchronized (this) { + waitAction(); this.currentCommand = null; - fileFrontEnd.onStoreAvailable(this); + fileFrontEnd.onStoreAvailable(this, responseCommand); + } + } + /** + * Permet au Store d'attendre une action à réaliser + */ + private void waitAction() { + synchronized (this) { try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } diff --git a/app/src/main/java/lightcontainer/enumerations/TaskStatus.java b/app/src/main/java/lightcontainer/enumerations/TaskStatus.java index 4113565..12200e6 100644 --- a/app/src/main/java/lightcontainer/enumerations/TaskStatus.java +++ b/app/src/main/java/lightcontainer/enumerations/TaskStatus.java @@ -6,8 +6,22 @@ import lightcontainer.domains.Task; * Enumeration defining the status of a {@link Task}. */ public enum TaskStatus { + + /** + * En attente d'être traitée + */ PENDING, + + /** + * En train d'être traitée + */ PROCESSING, + + /** + * Une erreur est survenue + */ ERROR, + + SUCCESS } diff --git a/app/src/main/java/lightcontainer/interfaces/StoreProcessorFFE.java b/app/src/main/java/lightcontainer/interfaces/StoreProcessorFFE.java index 5e95d5f..26be68b 100644 --- a/app/src/main/java/lightcontainer/interfaces/StoreProcessorFFE.java +++ b/app/src/main/java/lightcontainer/interfaces/StoreProcessorFFE.java @@ -1,6 +1,7 @@ package lightcontainer.interfaces; import lightcontainer.domains.client.StoreProcessor; +import lightcontainer.protocol.ProtocolWriter; import lightcontainer.repository.FileFrontEnd; /** @@ -10,6 +11,7 @@ public interface StoreProcessorFFE { /** * Allows a {@link StoreProcessor} to notify the FFE that it's available. * @param store The store processor that is now available. + * @param responseCommand */ - void onStoreAvailable(StoreProcessor store); + void onStoreAvailable(StoreProcessor store, ProtocolWriter.ProtocolResult response); } diff --git a/app/src/main/java/lightcontainer/interfaces/UnicastCHR.java b/app/src/main/java/lightcontainer/interfaces/UnicastCHR.java index 599093c..160b533 100644 --- a/app/src/main/java/lightcontainer/interfaces/UnicastCHR.java +++ b/app/src/main/java/lightcontainer/interfaces/UnicastCHR.java @@ -3,6 +3,7 @@ package lightcontainer.interfaces; import lightcontainer.domains.client.ClientHandler; import lightcontainer.domains.server.MulticastServerListener; import lightcontainer.domains.server.UnicastServerListener; +import lightcontainer.protocol.ProtocolWriter; import lightcontainer.repository.ClientHandlerRepository; /** @@ -20,4 +21,6 @@ public interface UnicastCHR { * @param client Client Handler to add. */ void addClient(ClientHandler client); + + void respondToClient(String client, ProtocolWriter.ProtocolResult response); } diff --git a/app/src/main/java/lightcontainer/protocol/ProtocolReader.java b/app/src/main/java/lightcontainer/protocol/ProtocolReader.java index 3715d73..54e3a9e 100644 --- a/app/src/main/java/lightcontainer/protocol/ProtocolReader.java +++ b/app/src/main/java/lightcontainer/protocol/ProtocolReader.java @@ -27,7 +27,7 @@ public abstract class ProtocolReader { /** * Command qui sera renvoyée par exemple au client */ - private String resultCommand; + private ProtocolWriter.ProtocolResult resultCommand; /** * Désigne vers ou cette commande est envoyée. @@ -44,7 +44,7 @@ public abstract class ProtocolReader { * Récupérer la commande à envoyer * @return Commande */ - public String getResultCommand() { + public ProtocolWriter.ProtocolResult getResultCommand() { return resultCommand; } @@ -53,7 +53,7 @@ public abstract class ProtocolReader { * @param resultCommand Commande à envoyer * @param receiver Le receveur de cette commande */ - public void setResultCommand(String resultCommand, ResultCmdReceiver receiver) { + public void setResultCommand(ProtocolWriter.ProtocolResult resultCommand, ResultCmdReceiver receiver) { this.resultCommand = resultCommand; this.receiver = receiver; } diff --git a/app/src/main/java/lightcontainer/protocol/ProtocolWriter.java b/app/src/main/java/lightcontainer/protocol/ProtocolWriter.java index 6b3801f..665609a 100644 --- a/app/src/main/java/lightcontainer/protocol/ProtocolWriter.java +++ b/app/src/main/java/lightcontainer/protocol/ProtocolWriter.java @@ -60,7 +60,7 @@ public abstract class ProtocolWriter { Matcher ruleMatcher = this.rulePattern.matcher(command); // Vérifie que tout match (cf. Matcher). Si match alors on retourne la commande build, sinon on retourne NULL if (ruleMatcher.matches()) { - ProtocolResult result = onExecuted(); + ProtocolResult result = onExecuted(data); result.setCommand(command); return (T) result; } @@ -70,6 +70,8 @@ public abstract class ProtocolWriter { /** * Cette méthode est appelée lors de l'exécution de la règle */ - protected abstract T onExecuted(); + protected T onExecuted(String... data) { + return (T) new ProtocolResult(); + } } diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/FilelistRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/FilelistRule.java index c544d61..3b292be 100644 --- a/app/src/main/java/lightcontainer/protocol/rules/reader/FilelistRule.java +++ b/app/src/main/java/lightcontainer/protocol/rules/reader/FilelistRule.java @@ -1,14 +1,21 @@ package lightcontainer.protocol.rules.reader; +import lightcontainer.interfaces.ProtocolRepository; import lightcontainer.protocol.ProtocolReader; +import lightcontainer.protocol.ProtocolWriter; +import lightcontainer.protocol.rules.writer.FilesRule; +import lightcontainer.protocol.rules.writer.SignOkRule; public class FilelistRule extends ProtocolReader { // Constants private static final String PATTERN = "^FILELIST\r\n$"; + private ProtocolRepository protocolRep; + // Constructor - public FilelistRule() { + public FilelistRule(ProtocolRepository protocolRep) { super(PATTERN); + this.protocolRep = protocolRep; } public class Result extends ProtocolResult { } @@ -20,7 +27,7 @@ public class FilelistRule extends ProtocolReader { @Override protected FilelistRule.Result onExecuted(String... data) { FilelistRule.Result result = new Result(); - result.setResultCommand("FILES endbenja.txt!500\r\n", ResultCmdReceiver.CLIENT); + result.setResultCommand(this.protocolRep.executeWriter(FilesRule.NAME, "endbenja.txt!500"), ResultCmdReceiver.CLIENT); return result; } } diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java index 1929480..a2565f1 100644 --- a/app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java +++ b/app/src/main/java/lightcontainer/protocol/rules/reader/SavefileRule.java @@ -1,6 +1,9 @@ package lightcontainer.protocol.rules.reader; +import lightcontainer.interfaces.ProtocolRepository; import lightcontainer.protocol.ProtocolReader; +import lightcontainer.protocol.rules.writer.SaveFileErrorRule; +import lightcontainer.protocol.rules.writer.SaveFileOkRule; import lightcontainer.utils.FileReceiver; import java.io.IOException; @@ -12,9 +15,12 @@ public class SavefileRule extends ProtocolReader { private static final int FILE_NAME = 0; // Index file name. private static final int FILE_SIZE = 1; // Index file size. + private ProtocolRepository protocolRep; + // Constructor - public SavefileRule() { + public SavefileRule(ProtocolRepository protocolRep) { super(PATTERN); + this.protocolRep = protocolRep; } public class Result extends ProtocolResult { @@ -38,9 +44,9 @@ public class SavefileRule extends ProtocolReader { if (!fileReceiver.receiveFile(reader, this.filename, this.size)) throw new IOException(); - this.setResultCommand("SAVEFILE_OK\r\n", ResultCmdReceiver.CLIENT); + this.setResultCommand(protocolRep.executeWriter(SaveFileOkRule.NAME), ResultCmdReceiver.CLIENT); } catch (IOException e) { - this.setResultCommand("SAVEFILE_ERROR\r\n", ResultCmdReceiver.CLIENT); + this.setResultCommand(protocolRep.executeWriter(SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT); e.printStackTrace(); } } diff --git a/app/src/main/java/lightcontainer/protocol/rules/reader/SigninRule.java b/app/src/main/java/lightcontainer/protocol/rules/reader/SigninRule.java index ad8006b..4e498dd 100644 --- a/app/src/main/java/lightcontainer/protocol/rules/reader/SigninRule.java +++ b/app/src/main/java/lightcontainer/protocol/rules/reader/SigninRule.java @@ -1,6 +1,9 @@ package lightcontainer.protocol.rules.reader; +import lightcontainer.interfaces.ProtocolRepository; import lightcontainer.protocol.ProtocolReader; +import lightcontainer.protocol.rules.writer.SignErrorRule; +import lightcontainer.protocol.rules.writer.SignOkRule; import java.io.InputStream; @@ -10,9 +13,12 @@ public class SigninRule extends ProtocolReader { private static final int LOGIN = 0; // Index du domain dans le tableau de données private static final int PASSWORD = 1; // Index du port dans le tableau de données + private ProtocolRepository protocolRep; + // Constructor - public SigninRule() { + public SigninRule(ProtocolRepository protocolRep) { super(PATTERN); + this.protocolRep = protocolRep; } public class Result extends ProtocolResult { @@ -50,9 +56,9 @@ public class SigninRule extends ProtocolReader { // TODO : Création d'une règle d'écriture SIGN_OK et SIGN_ERROR proprement if (result.checkCredentials()) { - result.setResultCommand("SIGN_OK\r\n", ResultCmdReceiver.CLIENT); + result.setResultCommand(this.protocolRep.executeWriter(SignOkRule.NAME), ResultCmdReceiver.CLIENT); } else { - result.setResultCommand("SIGN_ERROR\r\n", ResultCmdReceiver.CLIENT); + result.setResultCommand(this.protocolRep.executeWriter(SignErrorRule.NAME), ResultCmdReceiver.CLIENT); } return result; } diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/FilesRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/FilesRule.java new file mode 100644 index 0000000..7436141 --- /dev/null +++ b/app/src/main/java/lightcontainer/protocol/rules/writer/FilesRule.java @@ -0,0 +1,15 @@ +package lightcontainer.protocol.rules.writer; + +import lightcontainer.protocol.ProtocolWriter; + +public class FilesRule extends ProtocolWriter { + + private static final String PATTERN = "^FILES(( [^ !]{1,20})!([0-9]{1,10})){0,50}\r\n$"; + + public static final String NAME = "FILES"; + + public FilesRule() { + super(NAME, PATTERN); + } + +} diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileErrorRule.java new file mode 100644 index 0000000..8dda3a7 --- /dev/null +++ b/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileErrorRule.java @@ -0,0 +1,15 @@ +package lightcontainer.protocol.rules.writer; + +import lightcontainer.protocol.ProtocolWriter; + +public class SaveFileErrorRule extends ProtocolWriter { + + private static final String PATTERN = "^SAVEFILE_ERROR\r\n$"; + + public static final String NAME = "SAVEFILE_ERROR"; + + public SaveFileErrorRule() { + super(NAME, PATTERN); + } + +} diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileOkRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileOkRule.java new file mode 100644 index 0000000..1bd90d3 --- /dev/null +++ b/app/src/main/java/lightcontainer/protocol/rules/writer/SaveFileOkRule.java @@ -0,0 +1,15 @@ +package lightcontainer.protocol.rules.writer; + +import lightcontainer.protocol.ProtocolWriter; + +public class SaveFileOkRule extends ProtocolWriter { + + private static final String PATTERN = "^SAVEFILE_OK\r\n$"; + + public static final String NAME = "SAVEFILE_OK"; + + public SaveFileOkRule() { + super(NAME, PATTERN); + } + +} diff --git a/app/src/main/java/lightcontainer/protocol/rules/writer/SignErrorRule.java b/app/src/main/java/lightcontainer/protocol/rules/writer/SignErrorRule.java index 0c35635..b78a66f 100644 --- a/app/src/main/java/lightcontainer/protocol/rules/writer/SignErrorRule.java +++ b/app/src/main/java/lightcontainer/protocol/rules/writer/SignErrorRule.java @@ -11,4 +11,5 @@ public class SignErrorRule extends ProtocolWriter { public SignErrorRule() { super(NAME, PATTERN); } + } diff --git a/app/src/main/java/lightcontainer/repository/ClientHandlerRepository.java b/app/src/main/java/lightcontainer/repository/ClientHandlerRepository.java index e96050f..db1462d 100644 --- a/app/src/main/java/lightcontainer/repository/ClientHandlerRepository.java +++ b/app/src/main/java/lightcontainer/repository/ClientHandlerRepository.java @@ -3,6 +3,7 @@ package lightcontainer.repository; import lightcontainer.domains.client.ClientHandler; import lightcontainer.domains.server.UnicastServerListener; import lightcontainer.interfaces.UnicastCHR; +import lightcontainer.protocol.ProtocolWriter; import java.util.ArrayList; import java.util.List; @@ -54,6 +55,13 @@ public class ClientHandlerRepository implements AutoCloseable, UnicastCHR { this.handlers.add(client); } + @Override + public void respondToClient(String login, ProtocolWriter.ProtocolResult response) { + for (ClientHandler client : handlers) { + client.respond(response); + } + } + /** * AutoClosable Function * Closes all ClientHandlers stored in this repository and deallocates all resources. diff --git a/app/src/main/java/lightcontainer/repository/FileFrontEnd.java b/app/src/main/java/lightcontainer/repository/FileFrontEnd.java index ce47bea..bcd226e 100644 --- a/app/src/main/java/lightcontainer/repository/FileFrontEnd.java +++ b/app/src/main/java/lightcontainer/repository/FileFrontEnd.java @@ -5,8 +5,10 @@ import lightcontainer.domains.Task; import lightcontainer.interfaces.ClientHandlerFFE; import lightcontainer.interfaces.ProtocolRepository; import lightcontainer.interfaces.StoreProcessorFFE; +import lightcontainer.protocol.ProtocolWriter; import java.util.Deque; +import java.util.Iterator; import java.util.concurrent.ConcurrentLinkedDeque; public class FileFrontEnd implements ClientHandlerFFE, StoreProcessorFFE { @@ -28,16 +30,27 @@ public class FileFrontEnd implements ClientHandlerFFE, StoreProcessorFFE { */ public void alertStoreProcessors(Task task) { // On avertit les stor processors d'une nouvelle tâche + } /** * Permet à un {@link StoreProcessor} d'avertir le FFE qu'il est disponible * - * @param store + * @param store Le SBE qui s'est occupé de la tâche + * @param response La réponse à envoyer au client */ @Override - public void onStoreAvailable(StoreProcessor store) { + public void onStoreAvailable(StoreProcessor store, ProtocolWriter.ProtocolResult response) { + // TODO : Chercher une tâche appropriée + Iterator it = tasks.iterator(); + while (it.hasNext()) { + Task task = it.next(); + if (task.isResponseOfClient(store.getName())) { + clientRepository.respondToClient(task.getClient(), response); + it.remove(); // Suppression de la tâche + } + } } @Override