- Système de de lecture/ecriture fichier fini.

- Système de tâche presque fini et synchronisation. Reste à alerter SBE d'une nouvelle tâche et permettre à un SBE d'attendre un tâche
This commit is contained in:
Benjamin 2022-03-06 17:29:04 +01:00
parent 38a403d6a1
commit e3635b980b
18 changed files with 191 additions and 28 deletions

View File

@ -10,8 +10,7 @@ import lightcontainer.protocol.rules.reader.FilelistRule;
import lightcontainer.protocol.rules.reader.HelloRule; import lightcontainer.protocol.rules.reader.HelloRule;
import lightcontainer.protocol.rules.reader.SavefileRule; import lightcontainer.protocol.rules.reader.SavefileRule;
import lightcontainer.protocol.rules.reader.SigninRule; import lightcontainer.protocol.rules.reader.SigninRule;
import lightcontainer.protocol.rules.writer.SignErrorRule; import lightcontainer.protocol.rules.writer.*;
import lightcontainer.protocol.rules.writer.SignOkRule;
import lightcontainer.repository.ClientHandlerRepository; import lightcontainer.repository.ClientHandlerRepository;
import lightcontainer.repository.FileFrontEnd; import lightcontainer.repository.FileFrontEnd;
import lightcontainer.repository.ProtocolRepositoryImpl; import lightcontainer.repository.ProtocolRepositoryImpl;
@ -62,12 +61,15 @@ public class App {
ProtocolRepository protocolRep = new ProtocolRepositoryImpl(); ProtocolRepository protocolRep = new ProtocolRepositoryImpl();
protocolRep.addReader(new HelloRule()); protocolRep.addReader(new HelloRule());
protocolRep.addReader(new SigninRule()); protocolRep.addReader(new SigninRule(protocolRep));
protocolRep.addReader(new FilelistRule()); protocolRep.addReader(new FilelistRule(protocolRep));
protocolRep.addReader(new SavefileRule()); protocolRep.addReader(new SavefileRule(protocolRep));
protocolRep.addWriter(new SignOkRule()); protocolRep.addWriter(new SignOkRule());
protocolRep.addWriter(new SignErrorRule()); protocolRep.addWriter(new SignErrorRule());
protocolRep.addWriter(new FilesRule());
protocolRep.addWriter(new SaveFileOkRule());
protocolRep.addWriter(new SaveFileErrorRule());
new UnicastServerListener(clientRep, protocolRep, UNICAST_PORT); new UnicastServerListener(clientRep, protocolRep, UNICAST_PORT);
new MulticastServerListener(storeRep, protocolRep, MULTICAST_IP, MULTICAST_PORT); new MulticastServerListener(storeRep, protocolRep, MULTICAST_IP, MULTICAST_PORT);

View File

@ -5,7 +5,6 @@ import lightcontainer.enumerations.TaskType;
public class Task { public class Task {
// Variables // Variables
private TaskType type; // TODO : Supprimer car innutile ?
private TaskStatus status; private TaskStatus status;
private String command; private String command;
private String client; private String client;
@ -21,4 +20,21 @@ public class Task {
Task task = new Task(TaskStatus.PENDING, command, client); Task task = new Task(TaskStatus.PENDING, command, client);
return task; 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;
}
} }

View File

@ -41,6 +41,7 @@ public class ClientHandler implements Runnable, AutoCloseable {
private BufferedReader reader; private BufferedReader reader;
private PrintWriter writer; private PrintWriter writer;
private ProtocolWriter.ProtocolResult response;
// Constructor // Constructor
public ClientHandler(Socket client, ClientHandlerFFE ffe, ProtocolRepository protocolRep) { public ClientHandler(Socket client, ClientHandlerFFE ffe, ProtocolRepository protocolRep) {
@ -86,20 +87,27 @@ public class ClientHandler implements Runnable, AutoCloseable {
while (this.client_run) { while (this.client_run) {
try { try {
String command = this.reader.readLine(); String command = this.reader.readLine();
// TODO gestion de la réception de commandes, fichier, ...
if (command != null) System.out.println("Client: " + command); if (command != null) System.out.println("Client: " + command);
ProtocolReader.ProtocolResult ruleResult = protocolRep.executeReader(command + "\r\n"); ProtocolReader.ProtocolResult ruleResult = protocolRep.executeReader(command + "\r\n");
if (isConnected()) { if (isConnected()) {
ProtocolWriter.ProtocolResult writerCommand = ruleResult.getResultCommand();
ruleResult.read( ruleResult.read(
this.client.getInputStream() this.client.getInputStream()
); );
if (ruleResult.getReceiver() == ProtocolReader.ResultCmdReceiver.STOREBACKEND) { 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 { } else {
writer.write(ruleResult.getResultCommand()); // Renvoye au client writer.write(writerCommand.getCommand()); // Renvoye au client
writer.flush(); writer.flush();
} }
@ -107,6 +115,25 @@ public class ClientHandler implements Runnable, AutoCloseable {
authentication(ruleResult); authentication(ruleResult);
} }
} catch (IOException ignore) { } } 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();
} }
} }

View File

@ -79,7 +79,7 @@ public class StoreProcessor extends Thread implements AutoCloseable {
this.client_run = true; this.client_run = true;
while (this.client_run) { while (this.client_run) {
try { try {
alertAvalaible(); waitAction();
// Request // Request
ProtocolWriter.ProtocolResult requestResult = protocolRep.executeWriter(this.currentCommand); ProtocolWriter.ProtocolResult requestResult = protocolRep.executeWriter(this.currentCommand);
@ -92,8 +92,11 @@ public class StoreProcessor extends Thread implements AutoCloseable {
if (responseCommand != null) if (responseCommand != null)
System.out.println("StoreBackEnd: " + responseCommand); System.out.println("StoreBackEnd: " + responseCommand);
ProtocolReader.ProtocolResult responseResult = protocolRep.executeReader(responseCommand); ProtocolReader.ProtocolResult responseResult = protocolRep.executeReader(responseCommand);
responseResult.read(this.store.getInputStream());
System.out.println("StoreBackEnd response to client: " + responseResult.getResultCommand()); System.out.println("StoreBackEnd response to client: " + responseResult.getResultCommand());
alertAvalaible(responseResult.getResultCommand());
// TODO : Faire en sorte que getResultCommand retourne un ProtocolWriter
} catch (IOException ignore) { } } catch (IOException ignore) { }
} }
@ -113,12 +116,20 @@ public class StoreProcessor extends Thread implements AutoCloseable {
/** /**
* Permet de déclarer le StoreBackEnd disponible * Permet de déclarer le StoreBackEnd disponible
*/ */
private void alertAvalaible() { private void alertAvalaible(ProtocolWriter.ProtocolResult responseCommand) {
synchronized (this) { synchronized (this) {
waitAction();
this.currentCommand = null; 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 { try {
this.wait(); this.wait();
} catch (InterruptedException e) { e.printStackTrace(); } } catch (InterruptedException e) { e.printStackTrace(); }

View File

@ -6,8 +6,22 @@ import lightcontainer.domains.Task;
* Enumeration defining the status of a {@link Task}. * Enumeration defining the status of a {@link Task}.
*/ */
public enum TaskStatus { public enum TaskStatus {
/**
* En attente d'être traitée
*/
PENDING, PENDING,
/**
* En train d'être traitée
*/
PROCESSING, PROCESSING,
/**
* Une erreur est survenue
*/
ERROR, ERROR,
SUCCESS SUCCESS
} }

View File

@ -1,6 +1,7 @@
package lightcontainer.interfaces; package lightcontainer.interfaces;
import lightcontainer.domains.client.StoreProcessor; import lightcontainer.domains.client.StoreProcessor;
import lightcontainer.protocol.ProtocolWriter;
import lightcontainer.repository.FileFrontEnd; import lightcontainer.repository.FileFrontEnd;
/** /**
@ -10,6 +11,7 @@ public interface StoreProcessorFFE {
/** /**
* Allows a {@link StoreProcessor} to notify the FFE that it's available. * Allows a {@link StoreProcessor} to notify the FFE that it's available.
* @param store The store processor that is now available. * @param store The store processor that is now available.
* @param responseCommand
*/ */
void onStoreAvailable(StoreProcessor store); void onStoreAvailable(StoreProcessor store, ProtocolWriter.ProtocolResult response);
} }

View File

@ -3,6 +3,7 @@ package lightcontainer.interfaces;
import lightcontainer.domains.client.ClientHandler; import lightcontainer.domains.client.ClientHandler;
import lightcontainer.domains.server.MulticastServerListener; import lightcontainer.domains.server.MulticastServerListener;
import lightcontainer.domains.server.UnicastServerListener; import lightcontainer.domains.server.UnicastServerListener;
import lightcontainer.protocol.ProtocolWriter;
import lightcontainer.repository.ClientHandlerRepository; import lightcontainer.repository.ClientHandlerRepository;
/** /**
@ -20,4 +21,6 @@ public interface UnicastCHR {
* @param client Client Handler to add. * @param client Client Handler to add.
*/ */
void addClient(ClientHandler client); void addClient(ClientHandler client);
void respondToClient(String client, ProtocolWriter.ProtocolResult response);
} }

View File

@ -27,7 +27,7 @@ public abstract class ProtocolReader {
/** /**
* Command qui sera renvoyée par exemple au client * 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. * Désigne vers ou cette commande est envoyée.
@ -44,7 +44,7 @@ public abstract class ProtocolReader {
* Récupérer la commande à envoyer * Récupérer la commande à envoyer
* @return Commande * @return Commande
*/ */
public String getResultCommand() { public ProtocolWriter.ProtocolResult getResultCommand() {
return resultCommand; return resultCommand;
} }
@ -53,7 +53,7 @@ public abstract class ProtocolReader {
* @param resultCommand Commande à envoyer * @param resultCommand Commande à envoyer
* @param receiver Le receveur de cette commande * @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.resultCommand = resultCommand;
this.receiver = receiver; this.receiver = receiver;
} }

View File

@ -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 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()) { if (ruleMatcher.matches()) {
ProtocolResult result = onExecuted(); ProtocolResult result = onExecuted(data);
result.setCommand(command); result.setCommand(command);
return (T) result; 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 * Cette méthode est appelée lors de l'exécution de la règle
*/ */
protected abstract <T extends ProtocolResult> T onExecuted(); protected <T extends ProtocolResult> T onExecuted(String... data) {
return (T) new ProtocolResult();
}
} }

View File

@ -1,14 +1,21 @@
package lightcontainer.protocol.rules.reader; package lightcontainer.protocol.rules.reader;
import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.protocol.ProtocolReader; 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 { public class FilelistRule extends ProtocolReader {
// Constants // Constants
private static final String PATTERN = "^FILELIST\r\n$"; private static final String PATTERN = "^FILELIST\r\n$";
private ProtocolRepository protocolRep;
// Constructor // Constructor
public FilelistRule() { public FilelistRule(ProtocolRepository protocolRep) {
super(PATTERN); super(PATTERN);
this.protocolRep = protocolRep;
} }
public class Result extends ProtocolResult { } public class Result extends ProtocolResult { }
@ -20,7 +27,7 @@ public class FilelistRule extends ProtocolReader {
@Override @Override
protected FilelistRule.Result onExecuted(String... data) { protected FilelistRule.Result onExecuted(String... data) {
FilelistRule.Result result = new Result(); 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; return result;
} }
} }

View File

@ -1,6 +1,9 @@
package lightcontainer.protocol.rules.reader; package lightcontainer.protocol.rules.reader;
import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.protocol.ProtocolReader; import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.rules.writer.SaveFileErrorRule;
import lightcontainer.protocol.rules.writer.SaveFileOkRule;
import lightcontainer.utils.FileReceiver; import lightcontainer.utils.FileReceiver;
import java.io.IOException; 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_NAME = 0; // Index file name.
private static final int FILE_SIZE = 1; // Index file size. private static final int FILE_SIZE = 1; // Index file size.
private ProtocolRepository protocolRep;
// Constructor // Constructor
public SavefileRule() { public SavefileRule(ProtocolRepository protocolRep) {
super(PATTERN); super(PATTERN);
this.protocolRep = protocolRep;
} }
public class Result extends ProtocolResult { public class Result extends ProtocolResult {
@ -38,9 +44,9 @@ public class SavefileRule extends ProtocolReader {
if (!fileReceiver.receiveFile(reader, this.filename, this.size)) if (!fileReceiver.receiveFile(reader, this.filename, this.size))
throw new IOException(); throw new IOException();
this.setResultCommand("SAVEFILE_OK\r\n", ResultCmdReceiver.CLIENT); this.setResultCommand(protocolRep.executeWriter(SaveFileOkRule.NAME), ResultCmdReceiver.CLIENT);
} catch (IOException e) { } catch (IOException e) {
this.setResultCommand("SAVEFILE_ERROR\r\n", ResultCmdReceiver.CLIENT); this.setResultCommand(protocolRep.executeWriter(SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
e.printStackTrace(); e.printStackTrace();
} }
} }

View File

@ -1,6 +1,9 @@
package lightcontainer.protocol.rules.reader; package lightcontainer.protocol.rules.reader;
import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.protocol.ProtocolReader; import lightcontainer.protocol.ProtocolReader;
import lightcontainer.protocol.rules.writer.SignErrorRule;
import lightcontainer.protocol.rules.writer.SignOkRule;
import java.io.InputStream; 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 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 static final int PASSWORD = 1; // Index du port dans le tableau de données
private ProtocolRepository protocolRep;
// Constructor // Constructor
public SigninRule() { public SigninRule(ProtocolRepository protocolRep) {
super(PATTERN); super(PATTERN);
this.protocolRep = protocolRep;
} }
public class Result extends ProtocolResult { 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 // TODO : Création d'une règle d'écriture SIGN_OK et SIGN_ERROR proprement
if (result.checkCredentials()) { if (result.checkCredentials()) {
result.setResultCommand("SIGN_OK\r\n", ResultCmdReceiver.CLIENT); result.setResultCommand(this.protocolRep.executeWriter(SignOkRule.NAME), ResultCmdReceiver.CLIENT);
} else { } else {
result.setResultCommand("SIGN_ERROR\r\n", ResultCmdReceiver.CLIENT); result.setResultCommand(this.protocolRep.executeWriter(SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
} }
return result; return result;
} }

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -11,4 +11,5 @@ public class SignErrorRule extends ProtocolWriter {
public SignErrorRule() { public SignErrorRule() {
super(NAME, PATTERN); super(NAME, PATTERN);
} }
} }

View File

@ -3,6 +3,7 @@ package lightcontainer.repository;
import lightcontainer.domains.client.ClientHandler; import lightcontainer.domains.client.ClientHandler;
import lightcontainer.domains.server.UnicastServerListener; import lightcontainer.domains.server.UnicastServerListener;
import lightcontainer.interfaces.UnicastCHR; import lightcontainer.interfaces.UnicastCHR;
import lightcontainer.protocol.ProtocolWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -54,6 +55,13 @@ public class ClientHandlerRepository implements AutoCloseable, UnicastCHR {
this.handlers.add(client); this.handlers.add(client);
} }
@Override
public void respondToClient(String login, ProtocolWriter.ProtocolResult response) {
for (ClientHandler client : handlers) {
client.respond(response);
}
}
/** /**
* AutoClosable Function * AutoClosable Function
* Closes all ClientHandlers stored in this repository and deallocates all resources. * Closes all ClientHandlers stored in this repository and deallocates all resources.

View File

@ -5,8 +5,10 @@ import lightcontainer.domains.Task;
import lightcontainer.interfaces.ClientHandlerFFE; import lightcontainer.interfaces.ClientHandlerFFE;
import lightcontainer.interfaces.ProtocolRepository; import lightcontainer.interfaces.ProtocolRepository;
import lightcontainer.interfaces.StoreProcessorFFE; import lightcontainer.interfaces.StoreProcessorFFE;
import lightcontainer.protocol.ProtocolWriter;
import java.util.Deque; import java.util.Deque;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
public class FileFrontEnd implements ClientHandlerFFE, StoreProcessorFFE { public class FileFrontEnd implements ClientHandlerFFE, StoreProcessorFFE {
@ -28,16 +30,27 @@ public class FileFrontEnd implements ClientHandlerFFE, StoreProcessorFFE {
*/ */
public void alertStoreProcessors(Task task) { public void alertStoreProcessors(Task task) {
// On avertit les stor processors d'une nouvelle tâche // On avertit les stor processors d'une nouvelle tâche
} }
/** /**
* Permet à un {@link StoreProcessor} d'avertir le FFE qu'il est disponible * 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 @Override
public void onStoreAvailable(StoreProcessor store) { public void onStoreAvailable(StoreProcessor store, ProtocolWriter.ProtocolResult response) {
// TODO : Chercher une tâche appropriée
Iterator<Task> 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 @Override