Merge branch 'dev'
# Conflicts: # .idea/compiler.xml # .idea/discord.xml # .idea/misc.xml # gradle/wrapper/gradle-wrapper.jar # gradle/wrapper/gradle-wrapper.properties # gradlew
This commit is contained in:
commit
4974b64e18
6
.gitattributes
vendored
Normal file
6
.gitattributes
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
160
.gitignore
vendored
Normal file
160
.gitignore
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/gradle,java,intellij
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=gradle,java,intellij
|
||||
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Intellij Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||
.idea/**/sonarlint/
|
||||
|
||||
# SonarQube Plugin
|
||||
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||
.idea/**/sonarIssues.xml
|
||||
|
||||
# Markdown Navigator plugin
|
||||
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||
.idea/**/markdown-navigator.xml
|
||||
.idea/**/markdown-navigator-enh.xml
|
||||
.idea/**/markdown-navigator/
|
||||
|
||||
# Cache file creation bug
|
||||
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||
.idea/$CACHE_FILE$
|
||||
|
||||
# CodeStream plugin
|
||||
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||
.idea/codestream.xml
|
||||
|
||||
### Java ###
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
### Gradle ###
|
||||
.gradle
|
||||
**/build/
|
||||
!src/**/build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# Eclipse Gradle plugin generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/gradle,java,intellij
|
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="1.6" />
|
||||
<bytecodeTargetLevel target="11" />
|
||||
</component>
|
||||
</project>
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="ASK" />
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
<option name="description" value="" />
|
||||
</component>
|
||||
</project>
|
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="InfiniteLoopStatement" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
20
.idea/jarRepositories.xml
Normal file
20
.idea/jarRepositories.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
65
.idea/libraries-with-intellij-classes.xml
Normal file
65
.idea/libraries-with-intellij-classes.xml
Normal file
@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="libraries-with-intellij-classes">
|
||||
<option name="intellijApiContainingLibraries">
|
||||
<list>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="ideaIU" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.idea" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="ideaIU" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="ideaIC" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.idea" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="ideaIC" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="pycharmPY" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.pycharm" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="pycharmPY" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="pycharmPC" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.pycharm" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="pycharmPC" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="clion" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.clion" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="clion" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="riderRD" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.rider" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="riderRD" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="goland" />
|
||||
<option name="groupId" value="com.jetbrains.intellij.goland" />
|
||||
</LibraryCoordinatesState>
|
||||
<LibraryCoordinatesState>
|
||||
<option name="artifactId" value="goland" />
|
||||
<option name="groupId" value="com.jetbrains" />
|
||||
</LibraryCoordinatesState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
@ -4,5 +4,5 @@
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_6" project-jdk-name="11" project-jdk-type="JavaSDK" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK" />
|
||||
</project>
|
37
app/build.gradle
Normal file
37
app/build.gradle
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* This generated file contains a sample Java application project to get you started.
|
||||
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
|
||||
* User Manual available at https://docs.gradle.org/7.1/userguide/building_java_projects.html
|
||||
*/
|
||||
|
||||
plugins {
|
||||
// Apply the application plugin to add support for building a CLI application in Java.
|
||||
id 'application'
|
||||
}
|
||||
|
||||
repositories {
|
||||
// Use Maven Central for resolving dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Use JUnit Jupiter for testing.
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.7.1'
|
||||
|
||||
// This dependency is used by the application.
|
||||
implementation 'com.google.guava:guava:30.1-jre'
|
||||
// Use gson to serialize/deserialize json files
|
||||
implementation 'com.google.code.gson:gson:2.9.0'
|
||||
}
|
||||
|
||||
application {
|
||||
// Define the main class for the application.
|
||||
mainClass = 'lightcontainer.App'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
// Use JUnit Platform for unit tests.
|
||||
useJUnitPlatform()
|
||||
}
|
86
app/src/main/java/lightcontainer/App.java
Normal file
86
app/src/main/java/lightcontainer/App.java
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This Java source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package lightcontainer;
|
||||
|
||||
import lightcontainer.domains.server.MulticastServerListener;
|
||||
import lightcontainer.domains.server.UnicastServerListener;
|
||||
import lightcontainer.interfaces.ProtocolRepository;
|
||||
import lightcontainer.protocol.rules.reader.*;
|
||||
import lightcontainer.protocol.rules.writer.*;
|
||||
import lightcontainer.repository.ClientHandlerRepository;
|
||||
import lightcontainer.repository.FileFrontEnd;
|
||||
import lightcontainer.repository.ProtocolRepositoryImpl;
|
||||
import lightcontainer.repository.StoreProcessorRepository;
|
||||
|
||||
public class App {
|
||||
// Constant config server
|
||||
// -- Unicast client port
|
||||
private static final int UNICAST_PORT = 8000;
|
||||
// -- Multicast listener ip, port
|
||||
private static final String MULTICAST_IP = "226.66.66.1";
|
||||
private static final int MULTICAST_PORT = 15502;
|
||||
|
||||
|
||||
/*
|
||||
private static Thread t1 = null;
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
t1 = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int i = 0;
|
||||
while (true) {
|
||||
System.out.println("HEY " + i++);
|
||||
|
||||
try {
|
||||
synchronized (t1) {
|
||||
System.out.println("SUSPEND");
|
||||
t1.wait();
|
||||
}
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
t1.start();
|
||||
System.out.println("START");
|
||||
Thread.sleep(1000);
|
||||
synchronized (t1) {
|
||||
t1.notify();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
// Create all repository
|
||||
ClientHandlerRepository clientRep = new ClientHandlerRepository();
|
||||
StoreProcessorRepository storeRep = new StoreProcessorRepository();
|
||||
ProtocolRepository protocolRep = new ProtocolRepositoryImpl();
|
||||
|
||||
protocolRep.addReader(new HelloRule());
|
||||
protocolRep.addReader(new SigninRule(protocolRep));
|
||||
protocolRep.addReader(new FilelistRule(protocolRep));
|
||||
protocolRep.addReader(new SavefileRule(protocolRep));
|
||||
protocolRep.addReader(new SendOkRule(protocolRep));
|
||||
|
||||
protocolRep.addWriter(new SignOkRule());
|
||||
protocolRep.addWriter(new SignErrorRule());
|
||||
protocolRep.addWriter(new SignoutRule());
|
||||
protocolRep.addWriter(new FilesRule());
|
||||
protocolRep.addWriter(new SaveFileOkRule());
|
||||
protocolRep.addWriter(new SaveFileErrorRule());
|
||||
protocolRep.addWriter(new SendfileRule());
|
||||
|
||||
FileFrontEnd ffe = new FileFrontEnd(clientRep, storeRep, protocolRep);
|
||||
new UnicastServerListener(ffe, clientRep, protocolRep, UNICAST_PORT);
|
||||
new MulticastServerListener(ffe, storeRep, protocolRep, MULTICAST_IP, MULTICAST_PORT);
|
||||
|
||||
// close repo et client et server.
|
||||
|
||||
// Thread.sleep(60000);
|
||||
|
||||
// clientRep.close();
|
||||
// storeRep.close();
|
||||
}
|
||||
|
||||
}
|
52
app/src/main/java/lightcontainer/domains/Task.java
Normal file
52
app/src/main/java/lightcontainer/domains/Task.java
Normal file
@ -0,0 +1,52 @@
|
||||
package lightcontainer.domains;
|
||||
|
||||
import lightcontainer.enumerations.TaskStatus;
|
||||
import lightcontainer.enumerations.TaskType;
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
|
||||
public class Task {
|
||||
// Variables
|
||||
private TaskStatus status;
|
||||
private ProtocolWriter.ProtocolResult command;
|
||||
private String client;
|
||||
private String storeDomain;
|
||||
|
||||
public Task(TaskStatus status, ProtocolWriter.ProtocolResult command, String client) {
|
||||
this.status = status;
|
||||
this.command = command;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public static Task newInstance(ProtocolWriter.ProtocolResult command, String client) {
|
||||
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 (status == TaskStatus.PROCESSING && this.storeDomain.equals(storeDomain));
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de récupérer le login du client associé à la tâche
|
||||
* @return Login du client
|
||||
*/
|
||||
public String getClient() {
|
||||
return client;
|
||||
}
|
||||
|
||||
public ProtocolWriter.ProtocolResult getCommand() {
|
||||
return this.command;
|
||||
}
|
||||
|
||||
public void setDomain(String storeDomain) {
|
||||
this.storeDomain = storeDomain;
|
||||
if (storeDomain != null) {
|
||||
this.status = TaskStatus.PROCESSING;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
package lightcontainer.domains.client;
|
||||
|
||||
import lightcontainer.interfaces.ClientHandlerFFE;
|
||||
import lightcontainer.interfaces.ProtocolRepository;
|
||||
import lightcontainer.protocol.ProtocolReader;
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
import lightcontainer.protocol.rules.reader.SigninRule;
|
||||
import lightcontainer.protocol.rules.writer.SignErrorRule;
|
||||
import lightcontainer.protocol.rules.writer.SignOkRule;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* ClientHandler
|
||||
*
|
||||
* <!> UNICAST CLIENT <!>
|
||||
* Class communicating with the client, and
|
||||
* intercepting and sending files to the client.
|
||||
*
|
||||
* @version 1.1
|
||||
* @since 1.0
|
||||
*
|
||||
* @see Runnable
|
||||
* @see AutoCloseable
|
||||
* @author Jérémi NIHART <j.nihart@student.helmo.be>
|
||||
*/
|
||||
public class ClientHandler implements Runnable, AutoCloseable {
|
||||
// Variables
|
||||
private ClientHandlerFFE fileFrontEnd;
|
||||
private final Socket client;
|
||||
private ProtocolRepository protocolRep;
|
||||
private boolean client_run;
|
||||
|
||||
/**
|
||||
* Login of client.
|
||||
* State : NULL if not connected and Login string if connected
|
||||
*/
|
||||
private String login;
|
||||
|
||||
private BufferedReader reader;
|
||||
private PrintWriter writer;
|
||||
private ProtocolWriter.ProtocolResult response;
|
||||
|
||||
// Constructor
|
||||
public ClientHandler(Socket client, ClientHandlerFFE ffe, ProtocolRepository protocolRep) {
|
||||
this.fileFrontEnd = ffe;
|
||||
this.client = client;
|
||||
this.protocolRep = protocolRep;
|
||||
this.client_run = false;
|
||||
initClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the Client's Reader and Writer.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @see BufferedReader
|
||||
* @see PrintWriter
|
||||
*/
|
||||
private void initClient() {
|
||||
try {
|
||||
this.reader = new BufferedReader(new InputStreamReader(
|
||||
this.client.getInputStream(),
|
||||
StandardCharsets.UTF_8
|
||||
));
|
||||
this.writer = new PrintWriter(new OutputStreamWriter(
|
||||
this.client.getOutputStream(),
|
||||
StandardCharsets.UTF_8
|
||||
), true);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread Function
|
||||
* Start the dialogue with the client.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
this.client_run = true;
|
||||
while (this.client_run) {
|
||||
try {
|
||||
String command = this.reader.readLine();
|
||||
if (command != null) System.out.println("Client: " + command);
|
||||
|
||||
ProtocolReader.ProtocolResult ruleResult = protocolRep.executeReader(command + "\r\n");
|
||||
|
||||
if (isConnected()) {
|
||||
ruleResult.read(
|
||||
this.client.getInputStream()
|
||||
);
|
||||
ProtocolWriter.ProtocolResult writerCommand = ruleResult.getResultCommand();
|
||||
|
||||
if (ruleResult.getReceiver() == ProtocolReader.ResultCmdReceiver.STOREBACKEND) {
|
||||
fileFrontEnd.newCommand(
|
||||
writerCommand,
|
||||
getLogin()); // 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(writerCommand.getCommand()); // Renvoye au client
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
} else {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void authentication(ProtocolReader.ProtocolResult ruleResult) {
|
||||
try {
|
||||
SigninRule.Result signinResult = (SigninRule.Result) ruleResult;
|
||||
if (signinResult.checkCredentials()) {
|
||||
this.login = signinResult.getLogin();
|
||||
ProtocolWriter.ProtocolResult signokResult = protocolRep.executeWriter(SignOkRule.NAME);
|
||||
writer.write(signokResult.getCommand());
|
||||
writer.flush();
|
||||
return;
|
||||
}
|
||||
} catch (ClassCastException ignored) {}
|
||||
|
||||
ProtocolWriter.ProtocolResult signErrorResult = protocolRep.executeWriter(SignErrorRule.NAME);
|
||||
writer.write(signErrorResult.getCommand()); // Envoie SignError car echec de la connection
|
||||
writer.flush();
|
||||
this.close(); // Fermeture de la connection
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de savoir si l'utilisateur s'est connecté (Avec login et mdp)
|
||||
* @return
|
||||
*/
|
||||
private boolean isConnected() {
|
||||
return login != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* AutoClosable Function
|
||||
* Close the Client thread and resources.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
if (this.client_run) {
|
||||
try {
|
||||
this.client_run = false;
|
||||
this.client.close();
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return this.login;
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
package lightcontainer.domains.client;
|
||||
|
||||
import lightcontainer.domains.Task;
|
||||
import lightcontainer.interfaces.ProtocolRepository;
|
||||
import lightcontainer.interfaces.StoreProcessorFFE;
|
||||
import lightcontainer.protocol.ProtocolReader;
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* StoreProcessor
|
||||
*
|
||||
* <!> MULTICAST CLIENT <!>
|
||||
* Class communicating with the storebackend and
|
||||
* processing the tasks in the FileFrontEnd
|
||||
*
|
||||
* @version 1.1
|
||||
* @since 1.0
|
||||
*
|
||||
* @see Runnable
|
||||
* @see AutoCloseable
|
||||
* @author Jérémi NIHART <j.nihart@student.helmo.be>
|
||||
*/
|
||||
public class StoreProcessor extends Thread implements AutoCloseable {
|
||||
// Variables
|
||||
private final StoreProcessorFFE fileFrontEnd;
|
||||
private final Socket store;
|
||||
private final String domain;
|
||||
private boolean client_run;
|
||||
|
||||
private BufferedReader reader;
|
||||
private PrintWriter writer;
|
||||
private ProtocolWriter.ProtocolResult protocolResult;
|
||||
private ProtocolRepository protocolRep;
|
||||
|
||||
// Constructor
|
||||
public StoreProcessor(Socket socket, String domain, StoreProcessorFFE ffe, ProtocolRepository protocolRep) {
|
||||
this.domain = domain;
|
||||
this.fileFrontEnd = ffe;
|
||||
this.store = socket;
|
||||
this.protocolRep = protocolRep;
|
||||
this.client_run = false;
|
||||
initStore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the Store's Reader and Writer.
|
||||
*
|
||||
* @see BufferedReader
|
||||
* @see PrintWriter
|
||||
* @since 1.0
|
||||
*/
|
||||
private void initStore() {
|
||||
try {
|
||||
this.reader = new BufferedReader(new InputStreamReader(
|
||||
this.store.getInputStream(),
|
||||
StandardCharsets.UTF_8
|
||||
));
|
||||
this.writer = new PrintWriter(new OutputStreamWriter(
|
||||
this.store.getOutputStream(),
|
||||
StandardCharsets.UTF_8
|
||||
), true);
|
||||
|
||||
this.start();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread Function
|
||||
* Start the dialogue with the storebackend.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
this.client_run = true;
|
||||
while (this.client_run) {
|
||||
try {
|
||||
waitAction();
|
||||
System.out.println("[SBE] Envoie commande : " + protocolResult.getCommand());
|
||||
|
||||
// Request
|
||||
this.writer.write(protocolResult.getCommand());
|
||||
this.writer.flush();
|
||||
protocolResult.write(this.store.getOutputStream());
|
||||
|
||||
|
||||
// Response
|
||||
String responseCommand = this.reader.readLine() + "\r\n";
|
||||
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());
|
||||
|
||||
} catch (IOException ignore) { }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de demander au StoreBackEnd d'effectuer une commande
|
||||
* @param protocolResult La commande à effectuer
|
||||
*/
|
||||
public void executeCommand(ProtocolWriter.ProtocolResult protocolResult) {
|
||||
synchronized (this) {
|
||||
this.protocolResult = protocolResult;
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de déclarer le StoreBackEnd disponible
|
||||
*/
|
||||
private void alertAvalaible(ProtocolWriter.ProtocolResult responseCommand) {
|
||||
synchronized (this) {
|
||||
this.protocolResult = null;
|
||||
fileFrontEnd.onStoreAvailable(this, responseCommand);
|
||||
waitAction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet au Store d'attendre une action à réaliser
|
||||
*/
|
||||
private void waitAction() {
|
||||
synchronized (this) {
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException e) { e.printStackTrace(); }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AutoClosable Function
|
||||
* Close the Storage thread and resources.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
if (this.client_run) {
|
||||
try {
|
||||
this.client_run = false;
|
||||
this.store.close();
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two StoreProcessor object to check if equals.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
StoreProcessor that = (StoreProcessor) o;
|
||||
return Objects.equals(domain, that.domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(domain);
|
||||
}
|
||||
|
||||
public boolean canProcessTask(Task task) {
|
||||
return this.protocolResult == null; // Vérifier si tâche veut ce SBE
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return this.domain;
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package lightcontainer.domains.server;
|
||||
|
||||
import lightcontainer.domains.client.StoreProcessor;
|
||||
import lightcontainer.interfaces.MulticastSPR;
|
||||
import lightcontainer.interfaces.ProtocolRepository;
|
||||
import lightcontainer.protocol.ProtocolReader;
|
||||
import lightcontainer.protocol.rules.reader.HelloRule;
|
||||
import lightcontainer.repository.FileFrontEnd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* StoreMulticastRunnable
|
||||
* <p>
|
||||
* Class listening to the announcement of new StoreBackEnd.
|
||||
* Allowing it to be used as a storage unit.
|
||||
*
|
||||
* @author Jérémi NIHART <j.nihart@student.helmo.be>
|
||||
* @version 1.0
|
||||
* @see Runnable
|
||||
* @since 1.0
|
||||
*/
|
||||
public class MulticastServerListener implements Runnable {
|
||||
// Variable
|
||||
private final String multicast_address;
|
||||
private final int multicast_port;
|
||||
private FileFrontEnd ffe;
|
||||
private final MulticastSPR repository;
|
||||
private final ProtocolRepository protocolRep;
|
||||
|
||||
private final byte[] buffer = new byte[256];
|
||||
private MulticastSocket listener;
|
||||
|
||||
// Constructor
|
||||
public MulticastServerListener(FileFrontEnd ffe, MulticastSPR repository, ProtocolRepository protocolRep, String multicast_address, int multicast_port) {
|
||||
this.ffe = ffe;
|
||||
this.repository = repository;
|
||||
this.protocolRep = protocolRep;
|
||||
this.multicast_address = multicast_address;
|
||||
this.multicast_port = multicast_port;
|
||||
repository.setServerListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start Multicast listening on indicated port and IP group.
|
||||
*
|
||||
* @see MulticastSocket#receive(DatagramPacket)
|
||||
* @see DatagramPacket
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Create a new listening socket
|
||||
this.listener = new MulticastSocket(this.multicast_port);
|
||||
// Create an identifier for the multicast group on the specified ip
|
||||
InetAddress listener_group = InetAddress.getByName(this.multicast_address);
|
||||
// Creation of a packet for the information received
|
||||
DatagramPacket packet = new DatagramPacket(this.buffer, this.buffer.length);
|
||||
// Add the listener to the multicast group
|
||||
this.listener.joinGroup(listener_group);
|
||||
while (true) {
|
||||
// Read the packet received and build a string of characters
|
||||
this.listener.receive(packet);
|
||||
String data = new String(packet.getData(), 0, packet.getLength());
|
||||
// Create a new StoreBacked (try used in the case of an error to maintain the listening loop)
|
||||
try {
|
||||
// TODO Récupérer le port du message du packet et le setup (add description of the line).
|
||||
HelloRule.Result readerResult = protocolRep.executeReader(data);
|
||||
System.out.printf("Nouveau SBE : Domain=%s | Port=%d\n", readerResult.getDomain(), readerResult.getPort());
|
||||
|
||||
Socket socket = new Socket(packet.getAddress(), readerResult.getPort());
|
||||
|
||||
// Create the store processor
|
||||
StoreProcessor storeProcessor = new StoreProcessor(socket, readerResult.getDomain(), ffe, protocolRep); // TODO <!!!> : Voir comment on procède get via repo ou ici ?!
|
||||
|
||||
// Add the store processor to its repository
|
||||
this.repository.addStore(storeProcessor);
|
||||
} catch (IOException ignore) {
|
||||
ignore.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the MulticastSocket connection and aborts the listening and infinite listening loop.
|
||||
*
|
||||
* @see MulticastServerListener#run()
|
||||
* @since 1.0
|
||||
*/
|
||||
public void stop() {
|
||||
this.listener.close();
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package lightcontainer.domains.server;
|
||||
|
||||
import lightcontainer.domains.client.ClientHandler;
|
||||
import lightcontainer.interfaces.ProtocolRepository;
|
||||
import lightcontainer.interfaces.UnicastCHR;
|
||||
import lightcontainer.repository.FileFrontEnd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
public class UnicastServerListener implements Runnable {
|
||||
// Variables
|
||||
private ServerSocket server;
|
||||
private FileFrontEnd ffe;
|
||||
private final UnicastCHR repository;
|
||||
private ProtocolRepository protocolRep;
|
||||
private final int server_port;
|
||||
private boolean server_run;
|
||||
|
||||
// Constructor
|
||||
public UnicastServerListener(FileFrontEnd ffe, UnicastCHR repository, ProtocolRepository protocolRep, int port) {
|
||||
this.ffe = ffe;
|
||||
this.repository = repository;
|
||||
this.protocolRep = protocolRep;
|
||||
this.server_port = port;
|
||||
this.server_run = false;
|
||||
repository.setServerListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the server and starts it on the previously selected port.
|
||||
*
|
||||
* @since 1.0
|
||||
*
|
||||
* @see Thread#start()
|
||||
* @see ClientHandler
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Allow looping in the loop and create a socket server
|
||||
this.server_run = true;
|
||||
this.server = new ServerSocket(this.server_port);
|
||||
while (this.server_run) {
|
||||
// Accepting connection requests (blocking)
|
||||
Socket client = this.server.accept();
|
||||
System.out.println("New Client");
|
||||
// Create a new Handler client by passing these dependencies to it
|
||||
ClientHandler clientHandler = new ClientHandler(client, ffe, protocolRep); // TODO passer FileFrontEnd ou faire ca dans le repository ?!
|
||||
// Add the client handler to its repository (clienthandlerrepository)
|
||||
this.repository.addClient(clientHandler);
|
||||
// Start the thread
|
||||
(new Thread(clientHandler)).start();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the server and terminates the new connection.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
public void stop() {
|
||||
if (this.server_run) {
|
||||
try {
|
||||
this.server_run = false;
|
||||
this.server.close();
|
||||
} catch (IOException ignored) { }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package lightcontainer.enumerations;
|
||||
|
||||
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
|
||||
}
|
12
app/src/main/java/lightcontainer/enumerations/TaskType.java
Normal file
12
app/src/main/java/lightcontainer/enumerations/TaskType.java
Normal file
@ -0,0 +1,12 @@
|
||||
package lightcontainer.enumerations;
|
||||
|
||||
import lightcontainer.domains.Task;
|
||||
|
||||
/**
|
||||
* enumeration to define the type of a {@link Task}.
|
||||
*/
|
||||
public enum TaskType {
|
||||
SEND,
|
||||
RECEIVE,
|
||||
DELETE
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package lightcontainer.interfaces;
|
||||
|
||||
import lightcontainer.domains.client.ClientHandler;
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
import lightcontainer.repository.FileFrontEnd;
|
||||
|
||||
/**
|
||||
* A communication interface between a {@link ClientHandler} and the {@link FileFrontEnd}.
|
||||
*/
|
||||
public interface ClientHandlerFFE {
|
||||
// functions
|
||||
|
||||
/**
|
||||
* Demande le traitement d'une commande
|
||||
* @param command Commande à traiter
|
||||
* @param client identifiant du client à qui est affilié cette commande
|
||||
*/
|
||||
void newCommand(ProtocolWriter.ProtocolResult command, String client);
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package lightcontainer.interfaces;
|
||||
|
||||
import lightcontainer.domains.Task;
|
||||
import lightcontainer.domains.client.StoreProcessor;
|
||||
import lightcontainer.domains.server.MulticastServerListener;
|
||||
import lightcontainer.repository.StoreProcessorRepository;
|
||||
|
||||
/**
|
||||
* A communication interface between a {@link StoreProcessor} and the {@link StoreProcessorRepository}.
|
||||
*/
|
||||
public interface MulticastSPR {
|
||||
/**
|
||||
* Setter, allow to define the ServerListener of a repository.
|
||||
* @param server ServerListener to set as default.
|
||||
*/
|
||||
void setServerListener(MulticastServerListener server);
|
||||
|
||||
/**
|
||||
* Add a StorePorcessor.
|
||||
* @param store Store processor to add.
|
||||
*/
|
||||
void addStore(StoreProcessor store);
|
||||
|
||||
String findDomain(Task task);
|
||||
|
||||
void assignTask(String stor, Task task);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package lightcontainer.interfaces;
|
||||
|
||||
import lightcontainer.protocol.ProtocolReader;
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
|
||||
public interface ProtocolRepository {
|
||||
|
||||
<T extends ProtocolReader.ProtocolResult> T executeReader(String data);
|
||||
|
||||
<T extends ProtocolWriter.ProtocolResult> T executeWriter(String cmdName, String... data);
|
||||
|
||||
void addReader(ProtocolReader reader);
|
||||
|
||||
void addWriter(ProtocolWriter writer);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package lightcontainer.interfaces;
|
||||
|
||||
import lightcontainer.domains.client.StoreProcessor;
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
import lightcontainer.repository.FileFrontEnd;
|
||||
|
||||
/**
|
||||
* A communication interface between a {@link StoreProcessor} and the {@link FileFrontEnd}.
|
||||
*/
|
||||
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, ProtocolWriter.ProtocolResult response);
|
||||
}
|
26
app/src/main/java/lightcontainer/interfaces/UnicastCHR.java
Normal file
26
app/src/main/java/lightcontainer/interfaces/UnicastCHR.java
Normal file
@ -0,0 +1,26 @@
|
||||
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;
|
||||
|
||||
/**
|
||||
* A communication interface between a {@link ClientHandler} and the {@link ClientHandlerRepository}.
|
||||
*/
|
||||
public interface UnicastCHR {
|
||||
/**
|
||||
* Setter, allow to define the ServerListener of a repository.
|
||||
* @param server ServerListener to set as default.
|
||||
*/
|
||||
void setServerListener(UnicastServerListener server);
|
||||
|
||||
/**
|
||||
* Add a ClientHandler.
|
||||
* @param client Client Handler to add.
|
||||
*/
|
||||
void addClient(ClientHandler client);
|
||||
|
||||
void respondToClient(String client, ProtocolWriter.ProtocolResult response);
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package lightcontainer.protocol;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class ProtocolReader {
|
||||
// Variables
|
||||
private final Pattern rulePattern;
|
||||
|
||||
// Constructor
|
||||
protected ProtocolReader(String pattern) {
|
||||
this.rulePattern = Pattern.compile(pattern);
|
||||
}
|
||||
|
||||
public enum ResultCmdReceiver {
|
||||
CLIENT,
|
||||
STOREBACKEND
|
||||
}
|
||||
|
||||
/**
|
||||
* Modèle utilisé par tout les résultats des règles de protocol.
|
||||
* Lorsqu'il retourne son résultat, on vérifie si il y a une demande de lecture/écriture de fichier depuis le réseau. Si oui on appel ces méthodes, sinon on ne fait rien.
|
||||
* Ensuite on regarde après l'exécution de ces méthode ou non si il y a une commande de retour ou non et l'envoyons au receiver spécifié par la commande.
|
||||
*/
|
||||
public class ProtocolResult {
|
||||
/**
|
||||
* Command qui sera renvoyée par exemple au client
|
||||
*/
|
||||
private ProtocolWriter.ProtocolResult resultCommand;
|
||||
|
||||
/**
|
||||
* Désigne vers ou cette commande est envoyée.
|
||||
* ResultCmdReceiver.CLIENT : Signifie que cette commande va être directement revoyée au client.
|
||||
* ResultCmdReceiver.STOREBACKEND : Signifie que cette commande va être envoyée dans la file de tâche du server et êre en attente d'envoie à un StorBackEnd
|
||||
*/
|
||||
private ResultCmdReceiver receiver;
|
||||
|
||||
public ResultCmdReceiver getReceiver() {
|
||||
return receiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupérer la commande à envoyer
|
||||
* @return Commande
|
||||
*/
|
||||
public ProtocolWriter.ProtocolResult getResultCommand() {
|
||||
return this.resultCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mettre la commande à envoyer
|
||||
* @param resultCommand Commande à envoyer
|
||||
* @param receiver Le receveur de cette commande
|
||||
*/
|
||||
public void setResultCommand(ProtocolWriter.ProtocolResult resultCommand, ResultCmdReceiver receiver) {
|
||||
this.resultCommand = resultCommand;
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de lire un fichier. Cad reçevoir le contenu d'un fichier provenant du réseau.
|
||||
* Redéfinissez cette méthode pour l'utiliser
|
||||
* @param reader Buffer rempli du fichier
|
||||
*/
|
||||
public void read(InputStream reader) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de lancer la décomposition d'une commande pour en extraire les données
|
||||
* @param data Contenu de la commande
|
||||
*/
|
||||
public <T extends ProtocolResult> T execute(String data) {
|
||||
Matcher ruleMatcher = this.rulePattern.matcher(data);
|
||||
|
||||
if (ruleMatcher.matches()) {
|
||||
String[] groups = new String[ruleMatcher.groupCount()];
|
||||
|
||||
for (int i = 1; i <= groups.length; ++i)
|
||||
groups[i - 1] = ruleMatcher.group(i);
|
||||
|
||||
return onExecuted(groups);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cette méthode est appelée lors de l'exécution de la règle
|
||||
* @param data Paramètres pour créer la commande.
|
||||
*/
|
||||
protected abstract <T> T onExecuted(String... data);
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
package lightcontainer.protocol;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class ProtocolWriter {
|
||||
// Variables
|
||||
private final Pattern rulePattern;
|
||||
private final String cmdName;
|
||||
|
||||
// Constructor
|
||||
protected ProtocolWriter(String cmdName, String pattern) {
|
||||
this.rulePattern = Pattern.compile(pattern);
|
||||
this.cmdName = cmdName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de récupérer le nom de la commande.
|
||||
* @return Nom de la commande.
|
||||
*/
|
||||
public final String getCmdName() {
|
||||
return cmdName;
|
||||
}
|
||||
|
||||
public static class ProtocolResult {
|
||||
|
||||
private String command;
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
private void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet d'écrire un fichier sur le réseau. Cad envoyer le contenu d'un fichier sur le réseau.
|
||||
* Redéfinissez cette méthode pour l'utiliser.
|
||||
* @param writer Buffer à remplir qui sera envoyer via le réseau
|
||||
*/
|
||||
public void write(OutputStream writer) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de contruire une commande selon une règle établie.
|
||||
* @param data Les données à ajouter dans la commande; L'ordre défini leur position dans la commande
|
||||
* @return La commande construite
|
||||
*/
|
||||
public final <T extends ProtocolResult> T execute(String... data) {
|
||||
// Concatatène le nom de la commande avec les données (trim), avec un espace entre chaque
|
||||
StringBuilder builder = new StringBuilder(this.cmdName);
|
||||
|
||||
for (String param : data)
|
||||
builder.append(" " + param);
|
||||
|
||||
String command = builder + "\r\n";
|
||||
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(data);
|
||||
result.setCommand(command);
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cette méthode est appelée lors de l'exécution de la règle
|
||||
*/
|
||||
protected <T extends ProtocolResult> T onExecuted(String... data) {
|
||||
return (T) new ProtocolResult();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
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(ProtocolRepository protocolRep) {
|
||||
super(PATTERN);
|
||||
this.protocolRep = protocolRep;
|
||||
}
|
||||
|
||||
public class Result extends ProtocolResult { }
|
||||
|
||||
/**
|
||||
* Cette méthode est appelée lors de l'exécution de la règle
|
||||
* @param data Paramètres pour créer la commande.
|
||||
*/
|
||||
@Override
|
||||
protected FilelistRule.Result onExecuted(String... data) {
|
||||
FilelistRule.Result result = new Result();
|
||||
result.setResultCommand(this.protocolRep.executeWriter(FilesRule.NAME, "endbenja.txt!500"), ResultCmdReceiver.CLIENT);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package lightcontainer.protocol.rules.reader;
|
||||
|
||||
import lightcontainer.protocol.ProtocolReader;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class HelloRule extends ProtocolReader {
|
||||
|
||||
private static final String PATTERN = "^HELLO ([A-Za-z0-9]{5,20}) ([0-9]{1,5})\r\n$";
|
||||
|
||||
// Index du domain dans le tableau de donnée
|
||||
private static final int DOMAIN = 0;
|
||||
|
||||
//Index du port dans le tableau de donnée
|
||||
private static final int PORT = 1;
|
||||
|
||||
public HelloRule() {
|
||||
super(PATTERN);
|
||||
}
|
||||
|
||||
|
||||
public class Result extends ProtocolResult {
|
||||
|
||||
private final String domain;
|
||||
private final int port;
|
||||
|
||||
public Result(String domain, int port) {
|
||||
this.domain = domain;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected HelloRule.Result onExecuted(String... data) {
|
||||
String domain = data[DOMAIN];
|
||||
int port = Integer.parseInt(data[PORT]);
|
||||
|
||||
return new HelloRule.Result(domain, port);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
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.protocol.rules.writer.SendfileRule;
|
||||
import lightcontainer.utils.FileReceiver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class SavefileRule extends ProtocolReader {
|
||||
// Constants
|
||||
private static final String PATTERN = "^SAVEFILE ([^ !]{1,20}) ([0-9]{1,10})\r\n$";
|
||||
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(ProtocolRepository protocolRep) {
|
||||
super(PATTERN);
|
||||
this.protocolRep = protocolRep;
|
||||
}
|
||||
|
||||
public class Result extends ProtocolResult {
|
||||
// Variables
|
||||
private final String filename;
|
||||
private final int size;
|
||||
|
||||
// Construct
|
||||
public Result(String filename, int size) {
|
||||
this.filename = filename;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(InputStream reader) {
|
||||
super.read(reader);
|
||||
System.out.printf("Sauvegarde du fichier : %s %d\n", filename, size);
|
||||
|
||||
try {
|
||||
FileReceiver fileReceiver = new FileReceiver("/home/benjamin/ffe"); // "D:\\");
|
||||
if (!fileReceiver.receiveFile(reader, this.filename, this.size))
|
||||
throw new IOException();
|
||||
|
||||
this.setResultCommand(protocolRep.executeWriter(SendfileRule.NAME, this.filename, String.valueOf(this.size), "EMPREINTEBLBLBLBLBLABLABLBALBALBALBALBALBALBALBALBALABLBALBALBALABLABLABLABLABLABLABALBLABALABLABLABLABKJABKAHBHKBHJbhjvgkh"), ResultCmdReceiver.STOREBACKEND);
|
||||
} catch (IOException e) {
|
||||
this.setResultCommand(protocolRep.executeWriter(SaveFileErrorRule.NAME), ResultCmdReceiver.CLIENT);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cette méthode est appelée lors de l'exécution de la règle
|
||||
* @param data Paramètres pour créer la commande.
|
||||
*/
|
||||
@Override
|
||||
protected SavefileRule.Result onExecuted(String... data) {
|
||||
SavefileRule.Result result = new SavefileRule.Result(data[FILE_NAME], Integer.parseInt(data[FILE_SIZE]));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package lightcontainer.protocol.rules.reader;
|
||||
|
||||
import lightcontainer.interfaces.ProtocolRepository;
|
||||
import lightcontainer.protocol.ProtocolReader;
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
import lightcontainer.protocol.rules.writer.SaveFileOkRule;
|
||||
|
||||
public class SendOkRule extends ProtocolReader {
|
||||
|
||||
|
||||
// Constants
|
||||
private static final String PATTERN = "^SEND_OK\r\n$";
|
||||
|
||||
private ProtocolRepository protocolRep;
|
||||
|
||||
// Constructor
|
||||
public SendOkRule(ProtocolRepository protocolRep) {
|
||||
super(PATTERN);
|
||||
this.protocolRep = protocolRep;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ProtocolReader.ProtocolResult onExecuted(String... data) {
|
||||
ProtocolReader.ProtocolResult result = new ProtocolReader.ProtocolResult();
|
||||
result.setResultCommand(protocolRep.executeWriter(SaveFileOkRule.NAME), ResultCmdReceiver.CLIENT);
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
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;
|
||||
|
||||
public class SigninRule extends ProtocolReader {
|
||||
// Constants
|
||||
private static final String PATTERN = "^SIGNIN ([A-Za-z0-9]{2,20}) ([^ !]{5,50})\r\n$";
|
||||
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(ProtocolRepository protocolRep) {
|
||||
super(PATTERN);
|
||||
this.protocolRep = protocolRep;
|
||||
}
|
||||
|
||||
public class Result extends ProtocolResult {
|
||||
// Variables
|
||||
private final String login;
|
||||
private final String password;
|
||||
|
||||
// Result constructor
|
||||
public Result(String login, String password) {
|
||||
this.login = login;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public boolean checkCredentials() {
|
||||
return getLogin().equals("aa") && getPassword().equals("aaaaa");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(InputStream reader) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SigninRule.Result onExecuted(String... data) {
|
||||
SigninRule.Result result = new SigninRule.Result(data[LOGIN], data[PASSWORD]);
|
||||
|
||||
// TODO : Création d'une règle d'écriture SIGN_OK et SIGN_ERROR proprement
|
||||
if (result.checkCredentials()) {
|
||||
result.setResultCommand(this.protocolRep.executeWriter(SignOkRule.NAME), ResultCmdReceiver.CLIENT);
|
||||
} else {
|
||||
result.setResultCommand(this.protocolRep.executeWriter(SignErrorRule.NAME), ResultCmdReceiver.CLIENT);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package lightcontainer.protocol.rules.writer;
|
||||
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
import lightcontainer.utils.FileReceiver;
|
||||
import lightcontainer.utils.FileSender;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class SendfileRule extends ProtocolWriter {
|
||||
|
||||
private static final String PATTERN = "^SENDFILE [A-Za-z0-9.]{0,200} [0-9]{1,10} [A-Za-z0-9.]{50,200}\r\n$";
|
||||
|
||||
public static final String NAME = "SENDFILE";
|
||||
|
||||
private static final int HASHED_FILE_NAME = 0; // Index file name hashed.
|
||||
private static final int FILE_SIZE = 1; // Index file size.
|
||||
private static final int HASHED_FILE_CONTENT = 2; // Index file content hashed.
|
||||
|
||||
public SendfileRule() {
|
||||
super(NAME, PATTERN);
|
||||
}
|
||||
|
||||
public class Result extends ProtocolWriter.ProtocolResult {
|
||||
|
||||
private final String hashedFileName;
|
||||
private final int fileSize;
|
||||
private final String hashedFileContent;
|
||||
|
||||
public Result(String hashedFileName, int fileSize, String hashedFileContent) {
|
||||
this.hashedFileName = hashedFileName;
|
||||
this.fileSize = fileSize;
|
||||
this.hashedFileContent = hashedFileContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(OutputStream writer) {
|
||||
super.write(writer);
|
||||
System.out.println("Envoie du fichier au SBE");
|
||||
FileSender fileSender = new FileSender("/home/benjamin/ffe");
|
||||
fileSender.sendFile(hashedFileName, writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected SendfileRule.Result onExecuted(String... data) {
|
||||
return new SendfileRule.Result(data[HASHED_FILE_NAME], Integer.parseInt(data[FILE_SIZE]), data[HASHED_FILE_CONTENT]);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package lightcontainer.protocol.rules.writer;
|
||||
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
|
||||
public class SignErrorRule extends ProtocolWriter {
|
||||
|
||||
private static final String PATTERN = "^SIGN_ERROR\r\n$";
|
||||
|
||||
public static final String NAME = "SIGN_ERROR";
|
||||
|
||||
public SignErrorRule() {
|
||||
super(NAME, PATTERN);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package lightcontainer.protocol.rules.writer;
|
||||
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
|
||||
public class SignOkRule extends ProtocolWriter {
|
||||
|
||||
private static final String PATTERN = "^SIGN_OK\r\n$";
|
||||
|
||||
public static final String NAME = "SIGN_OK";
|
||||
|
||||
public SignOkRule() {
|
||||
super(NAME, PATTERN);
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package lightcontainer.protocol.rules.writer;
|
||||
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
|
||||
public class SignoutRule extends ProtocolWriter {
|
||||
|
||||
private static final String PATTERN = "^SIGNOUT\r\n$";
|
||||
|
||||
public static final String NAME = "SIGNOUT";
|
||||
|
||||
public SignoutRule() {
|
||||
super(NAME, PATTERN);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
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;
|
||||
// TODO : C'est genre un ClientHandlerManager quoi hein, normal qu'il fasse blinder de chose ;)
|
||||
/**
|
||||
* ClientHandlerRepository
|
||||
*
|
||||
* Repository storing ClientHandler class.
|
||||
* Contains some utility functions.
|
||||
*
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*
|
||||
* @see ClientHandler
|
||||
* @see AutoCloseable
|
||||
* @author Jérémi NIHART <j.nihart@student.helmo.be>
|
||||
*/
|
||||
public class ClientHandlerRepository implements AutoCloseable, UnicastCHR {
|
||||
// Variable
|
||||
private final List<ClientHandler> handlers;
|
||||
private UnicastServerListener server;
|
||||
|
||||
// Constructor
|
||||
public ClientHandlerRepository() {
|
||||
this.handlers = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter, allow to define the ServerListener of a repository.
|
||||
* & Start the server.
|
||||
* @param server ServerListener to set as default.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void setServerListener(UnicastServerListener server) {
|
||||
this.server = server;
|
||||
new Thread(server).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a ClientHandler.
|
||||
* @param client Client Handler to add.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void addClient(ClientHandler client) {
|
||||
this.handlers.add(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void respondToClient(String login, ProtocolWriter.ProtocolResult response) {
|
||||
for (ClientHandler client : handlers) {
|
||||
if (client.getLogin().equals(login)) {
|
||||
client.respond(response);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AutoClosable Function
|
||||
* Closes all ClientHandlers stored in this repository and deallocates all resources.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
// Stop the server.
|
||||
this.server.stop();
|
||||
// Stop each clients.
|
||||
this.handlers.forEach(ClientHandler::close);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package lightcontainer.repository;
|
||||
|
||||
import lightcontainer.domains.client.StoreProcessor;
|
||||
import lightcontainer.domains.Task;
|
||||
import lightcontainer.enumerations.TaskStatus;
|
||||
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 {
|
||||
// Variables
|
||||
private Deque<Task> tasks = new ConcurrentLinkedDeque<>();
|
||||
private ClientHandlerRepository clientRepository; // TODO -> pourquoi pas une interface ? end
|
||||
private StoreProcessorRepository storeRepository; // TODO -> pourquoi pas une interface ? end
|
||||
private ProtocolRepository protocolRepository;
|
||||
|
||||
// Constructor
|
||||
public FileFrontEnd(ClientHandlerRepository clientRepo, StoreProcessorRepository storeRepo, ProtocolRepository protocolRepository) {
|
||||
this.clientRepository = clientRepo;
|
||||
this.storeRepository = storeRepo;
|
||||
this.protocolRepository = protocolRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appelé quand nouvelle tâche
|
||||
*/
|
||||
public void alertStoreProcessors(Task task) {
|
||||
// On avertit les stor processors d'une nouvelle tâche
|
||||
String stor = storeRepository.findDomain(task);
|
||||
if (stor != null) {
|
||||
storeRepository.assignTask(stor, task);
|
||||
task.setDomain(stor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet à un {@link StoreProcessor} d'avertir le FFE qu'il est disponible
|
||||
*
|
||||
* @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, ProtocolWriter.ProtocolResult response) {
|
||||
// TODO : Chercher une tâche appropriée
|
||||
if (response != null) {
|
||||
Iterator<Task> it = tasks.iterator();
|
||||
while (it.hasNext()) {
|
||||
Task task = it.next();
|
||||
if (task.isResponseOfClient(store.getDomain())) {
|
||||
clientRepository.respondToClient(task.getClient(), response);
|
||||
it.remove(); // Suppression de la tâche
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assignOtherTask(store);
|
||||
}
|
||||
|
||||
private void assignOtherTask(StoreProcessor store) {
|
||||
Iterator<Task> it = tasks.iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
Task task = it.next();
|
||||
if (store.canProcessTask(task)) {
|
||||
storeRepository.assignTask(store.getDomain(), task);
|
||||
task.setDomain(store.getDomain());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void newCommand(ProtocolWriter.ProtocolResult command, String client) {
|
||||
Task task = Task.newInstance(command, client);
|
||||
tasks.add(task);
|
||||
alertStoreProcessors(task);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package lightcontainer.repository;
|
||||
|
||||
import lightcontainer.interfaces.ProtocolRepository;
|
||||
import lightcontainer.protocol.ProtocolReader;
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ProtocolRepositoryImpl implements ProtocolRepository {
|
||||
private final Set<ProtocolReader> readers = new HashSet<>();
|
||||
private final Set<ProtocolWriter> writers = new HashSet<>();
|
||||
|
||||
@Override
|
||||
public <T extends ProtocolReader.ProtocolResult> T executeReader(String data) {
|
||||
for (ProtocolReader reader : readers) {
|
||||
T readerResult = reader.execute(data);
|
||||
if (readerResult != null) {
|
||||
return readerResult;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends ProtocolWriter.ProtocolResult> T executeWriter(String cmdName, String... data) {
|
||||
for (ProtocolWriter writer : writers) {
|
||||
T command;
|
||||
if (cmdName.equals(writer.getCmdName()) && (command = writer.execute(data)) != null) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addReader(ProtocolReader reader) {
|
||||
this.readers.add(reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addWriter(ProtocolWriter writer) {
|
||||
this.writers.add(writer);
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package lightcontainer.repository;
|
||||
|
||||
import lightcontainer.domains.Task;
|
||||
import lightcontainer.domains.client.StoreProcessor;
|
||||
import lightcontainer.domains.server.MulticastServerListener;
|
||||
import lightcontainer.interfaces.MulticastSPR;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
// TODO : C'est genre un ClientHandlerManager quoi hein, normal qu'il fasse blinder de chose ;)
|
||||
/**
|
||||
* StoreProcessorRepository
|
||||
*
|
||||
* Repository storing StorePorcessor class.
|
||||
* Contains some utility functions.
|
||||
*
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*
|
||||
* @see StoreProcessor
|
||||
* @author Jérémi NIHART <j.nihart@student.helmo.be>
|
||||
*/
|
||||
public class StoreProcessorRepository implements AutoCloseable, MulticastSPR {
|
||||
// Variables
|
||||
private final Set<StoreProcessor> handlers;
|
||||
private MulticastServerListener server;
|
||||
|
||||
// Constructor
|
||||
public StoreProcessorRepository() {
|
||||
this.handlers = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter, allow to define the ServerListener of a repository.
|
||||
* & start the server.
|
||||
* @param server ServerListener to set as default.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void setServerListener(MulticastServerListener server) {
|
||||
this.server = server;
|
||||
new Thread(server).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a StorePorcessor.
|
||||
* @param store Store processor to add.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void addStore(StoreProcessor store) {
|
||||
this.handlers.add(store);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String findDomain(Task task) {
|
||||
StoreProcessor handler = findSBE(task);
|
||||
return handler == null ? null : handler.getDomain();
|
||||
}
|
||||
|
||||
private StoreProcessor findSBE(Task task) {
|
||||
for (StoreProcessor handler : handlers) {
|
||||
if (handler.canProcessTask(task)) {
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assignTask(String stor, Task task) {
|
||||
StoreProcessor handler = findSBE(task);
|
||||
handler.executeCommand(task.getCommand());
|
||||
}
|
||||
|
||||
/**
|
||||
* AutoClosable Function
|
||||
* Closes all StoreProcessor stored in this repository and deallocates all resources.
|
||||
*
|
||||
* @since 1.0
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
// Stop the server.
|
||||
this.server.stop();
|
||||
// Close each client.
|
||||
this.handlers.forEach(StoreProcessor::close);
|
||||
}
|
||||
}
|
8
app/src/main/java/lightcontainer/storage/Adapter.java
Normal file
8
app/src/main/java/lightcontainer/storage/Adapter.java
Normal file
@ -0,0 +1,8 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
public interface Adapter {
|
||||
|
||||
String toString();
|
||||
|
||||
AppData fromString(String appDataString);
|
||||
}
|
88
app/src/main/java/lightcontainer/storage/AppConfig.java
Normal file
88
app/src/main/java/lightcontainer/storage/AppConfig.java
Normal file
@ -0,0 +1,88 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
/**
|
||||
* AppConfig represents all network related information needed for the program to work.
|
||||
*
|
||||
* @author Maximilien LEDOUX <m.ledoux@student.helmo.be>
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*/
|
||||
public class AppConfig {
|
||||
|
||||
private static AppConfig instance = null;
|
||||
private int unicastPort;
|
||||
private String multicastIp;
|
||||
private int multicastPort;
|
||||
private String networkInterface;
|
||||
private boolean isTls;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of AppConfig.
|
||||
* Sets all data to default values.
|
||||
*/
|
||||
private AppConfig() {
|
||||
this.unicastPort = -1;
|
||||
this.multicastIp = "NONE";
|
||||
this.multicastPort = -1;
|
||||
this.networkInterface = "NONE";
|
||||
this.isTls = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An instance of this class. Always returns the same instance.
|
||||
*/
|
||||
public static AppConfig getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AppConfig();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public int getUnicastPort() {
|
||||
return unicastPort;
|
||||
}
|
||||
|
||||
public void setUnicastPort(int unicastPort) {
|
||||
if (this.unicastPort == -1) {
|
||||
this.unicastPort = unicastPort;
|
||||
}
|
||||
}
|
||||
|
||||
public String getMulticastIp() {
|
||||
return multicastIp;
|
||||
}
|
||||
|
||||
public void setMulticastIp(String multicastIp) {
|
||||
if (this.multicastIp.equals("NONE")) {
|
||||
this.multicastIp = multicastIp;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMulticastPort() {
|
||||
return multicastPort;
|
||||
}
|
||||
|
||||
public void setMulticastPort(int multicastPort) {
|
||||
if (this.multicastPort == -1) {
|
||||
this.multicastPort = multicastPort;
|
||||
}
|
||||
}
|
||||
|
||||
public String getNetworkInterface() {
|
||||
return networkInterface;
|
||||
}
|
||||
|
||||
public void setNetworkInterface(String networkInterface) {
|
||||
if (this.networkInterface.equals("NONE")) {
|
||||
this.networkInterface = networkInterface;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isTls() {
|
||||
return isTls;
|
||||
}
|
||||
|
||||
public void setTls(boolean tls) {
|
||||
this.isTls = tls;
|
||||
}
|
||||
}
|
152
app/src/main/java/lightcontainer/storage/AppData.java
Normal file
152
app/src/main/java/lightcontainer/storage/AppData.java
Normal file
@ -0,0 +1,152 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AppData represents the database of the FileFrontEnd program.
|
||||
* It contains an AppConfig instance and a collection of Users.
|
||||
*
|
||||
* @author Maximilien LEDOUX <m.ledoux@student.helmo.be>
|
||||
* @version 1.0
|
||||
* @see AppConfig
|
||||
* @see User
|
||||
* @since 1.0
|
||||
*/
|
||||
public class AppData {
|
||||
|
||||
private static AppData instance = null;
|
||||
private AppConfig appConfig;
|
||||
private final Map<String, User> users;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new instance of AppData.
|
||||
* Sets appConfig to null and creates a new Hashmap of users.
|
||||
*/
|
||||
private AppData() {
|
||||
this.appConfig = null;
|
||||
this.users = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return An instance of this class. Always returns the same instance.
|
||||
*/
|
||||
public static AppData getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new AppData();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The AppConfig
|
||||
*/
|
||||
public AppConfig getAppConfig() {
|
||||
return appConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the AppConfig. This method sets the AppConfig for once and for all.
|
||||
* It is locked after first call.
|
||||
*
|
||||
* @param appConfig The network configuration of the program.
|
||||
*/
|
||||
public void setAppConfig(AppConfig appConfig) {
|
||||
if (this.appConfig == null) {
|
||||
this.appConfig = appConfig;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param userName The name of the user.
|
||||
* @return The user corresponding to userName, null otherwise.
|
||||
*/
|
||||
public User getUser(String userName) {
|
||||
return this.users.get(userName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this method when a user signs up.
|
||||
*
|
||||
* @param user The user to add.
|
||||
* @return True if the user was added. False if a user with the same name already exists.
|
||||
*/
|
||||
public boolean addUser(User user) {
|
||||
if (this.users.containsKey(user.getName())) {
|
||||
return false;
|
||||
} else {
|
||||
this.users.put(user.getName(), user);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<User> usersIterator() {
|
||||
return users.values().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileName The name of the file
|
||||
* @param user The user
|
||||
* @return The file corresponding to the given name and belonging to the user. Null if the user cannot be found or the file cannot be found
|
||||
* @deprecated Maybe not useful. DO NOT USE FOR THE TIME BEING
|
||||
*/
|
||||
public File getFileOf(String fileName, User user) {
|
||||
return this.users.get(user.getName()).getFile(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method after receiving SAVEFILE_OK from the StorBackEnd.
|
||||
* Do NOT call when receiving SAVEFILE_ERROR, or it will break the system's synchronization.
|
||||
* <p>
|
||||
* Adds the file of for a specific user.
|
||||
* True indicates the success of the operation.
|
||||
* False indicates the failure of the operation.
|
||||
*
|
||||
* @param file The file to add
|
||||
* @param user The user who wants to add the file
|
||||
* @return True if the user is found and a file with the same name doesn't already exist for this user. False otherwise.
|
||||
*/
|
||||
public boolean addFileFor(File file, User user) {
|
||||
if (!this.users.containsKey(user.getName())) {
|
||||
return false;
|
||||
} else {
|
||||
this.users.get(user.getName()).addFile(file);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method after receiving REMOVEFILE_OK from the StorBackEnd.
|
||||
* Do NOT call when receiving REMOVEFILE_ERROR, or it will break the system's synchronization.
|
||||
* Deletes the file of for a specific user.
|
||||
* True indicates the success of the operation.
|
||||
* False indicates the failure of the operation.
|
||||
*
|
||||
* @param fileName The name of the file to delete
|
||||
* @param user The user who wants to delete the file
|
||||
* @return True if the user is found and the file was deleted. False otherwise.
|
||||
*/
|
||||
public boolean deleteFileOf(String fileName, User user) {
|
||||
if (!this.users.containsKey(user.getName())) {
|
||||
return false;
|
||||
} else {
|
||||
return this.users.get(user.getName()).deleteFile(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param user The user who wants to add a storage for their file
|
||||
* @param file The file that needs a new storage
|
||||
* @param storage The storage to add
|
||||
* @return True if the storage was added. False otherwise.
|
||||
*/
|
||||
public boolean addStorage(User user, File file, String storage) {
|
||||
if (!this.users.containsKey(user.getName())) {
|
||||
return false;
|
||||
} else {
|
||||
return this.users.get(user.getName()).addStorage(file, storage);
|
||||
}
|
||||
}
|
||||
}
|
47
app/src/main/java/lightcontainer/storage/File.java
Normal file
47
app/src/main/java/lightcontainer/storage/File.java
Normal file
@ -0,0 +1,47 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* File represents all information related to a file
|
||||
*/
|
||||
public class File {
|
||||
|
||||
private final String name;
|
||||
private final int size;
|
||||
private final String iv;
|
||||
private final Set<String> storage;
|
||||
|
||||
public File(String name, int size, String iv, Set<String> storage) {
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.iv = iv;
|
||||
this.storage = storage;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public String getIv() {
|
||||
return iv;
|
||||
}
|
||||
|
||||
public Iterator<String> getStorageIterator() {
|
||||
return storage.iterator();
|
||||
}
|
||||
|
||||
public boolean addStorage(String storage) {
|
||||
if (this.storage.contains(storage)) {
|
||||
return false;
|
||||
} else {
|
||||
this.storage.add(storage);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
145
app/src/main/java/lightcontainer/storage/JsonAdapter.java
Normal file
145
app/src/main/java/lightcontainer/storage/JsonAdapter.java
Normal file
@ -0,0 +1,145 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
import com.google.gson.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Specific implementation of Adapter that converts AppData to Json and vice-versa
|
||||
*/
|
||||
public class JsonAdapter implements Adapter {
|
||||
|
||||
private AppData appData;
|
||||
|
||||
public JsonAdapter(AppData appData) {
|
||||
this.appData = appData;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return A Json String containing AppData properties
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return addData(appData);
|
||||
}
|
||||
|
||||
private String addData(AppData appData) {
|
||||
AppConfig appConfig = appData.getAppConfig();
|
||||
JsonObject config = new JsonObject();
|
||||
config.addProperty("unicast_port", appConfig.getUnicastPort());
|
||||
config.addProperty("multicast_ip", appConfig.getMulticastIp());
|
||||
config.addProperty("multicast_port", appConfig.getMulticastPort());
|
||||
config.addProperty("network_interface", appConfig.getNetworkInterface());
|
||||
config.addProperty("tls", appConfig.isTls());
|
||||
JsonArray users = new JsonArray();
|
||||
Iterator<User> userIterator = appData.usersIterator();
|
||||
addUsers(users, userIterator);
|
||||
config.add("users", users);
|
||||
return config.toString();
|
||||
}
|
||||
|
||||
private void addUsers(JsonArray users, Iterator<User> userIterator) {
|
||||
while (userIterator.hasNext()) {
|
||||
User current = userIterator.next();
|
||||
JsonObject user = new JsonObject();
|
||||
user.addProperty("name", current.getName());
|
||||
user.addProperty("password", current.getPassword());
|
||||
user.addProperty("aes_key", current.getAesKey());
|
||||
JsonArray files = new JsonArray();
|
||||
Iterator<File> fileIterator = current.fileIterator();
|
||||
addFiles(fileIterator, files);
|
||||
user.add("files", files);
|
||||
users.add(user);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFiles(Iterator<File> fileIterator, JsonArray files) {
|
||||
while (fileIterator.hasNext()) {
|
||||
File currentFile = fileIterator.next();
|
||||
JsonObject file = new JsonObject();
|
||||
file.addProperty("name", currentFile.getName());
|
||||
file.addProperty("size", currentFile.getSize());
|
||||
file.addProperty("iv", currentFile.getIv());
|
||||
JsonArray storage = new JsonArray();
|
||||
Iterator<String> storageIterator = currentFile.getStorageIterator();
|
||||
addStorage(storage, storageIterator);
|
||||
file.add("storage", storage);
|
||||
files.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
private void addStorage(JsonArray storage, Iterator<String> storageIterator) {
|
||||
while (storageIterator.hasNext()) {
|
||||
String storageString = storageIterator.next();
|
||||
storage.add(storageString);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param appDataString The Json String to convert
|
||||
* @return An AppData instance
|
||||
*/
|
||||
@Override
|
||||
public AppData fromString(String appDataString) {
|
||||
try {
|
||||
JsonElement jsonString = JsonParser.parseString(appDataString);
|
||||
JsonObject jsonAppData = jsonString.getAsJsonObject();
|
||||
AppConfig appConfig = AppConfig.getInstance();
|
||||
appConfig.setUnicastPort(jsonAppData.get("unicast_port").getAsInt());
|
||||
appConfig.setMulticastIp(jsonAppData.get("multicast_ip").getAsString());
|
||||
appConfig.setMulticastPort(jsonAppData.get("multicast_port").getAsInt());
|
||||
appConfig.setNetworkInterface(jsonAppData.get("network_interface").getAsString());
|
||||
appConfig.setTls(jsonAppData.get("tls").getAsBoolean());
|
||||
JsonArray jsonUsers = jsonAppData.getAsJsonArray("users");
|
||||
List<User> users = new ArrayList<>();
|
||||
getUsers(jsonUsers, users);
|
||||
AppData appData = AppData.getInstance();
|
||||
appData.setAppConfig(appConfig);
|
||||
for (User user : users) {
|
||||
appData.addUser(user);
|
||||
}
|
||||
this.appData = appData;
|
||||
return this.appData;
|
||||
} catch (JsonParseException parseException) {
|
||||
System.out.println("[FFE] : Error while loading configuration file"); //TODO - changer en log
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void getUsers(JsonArray jsonUsers, List<User> users) {
|
||||
for (JsonElement element : jsonUsers) {
|
||||
JsonObject jsonUser = element.getAsJsonObject();
|
||||
String name = jsonUser.get("name").getAsString();
|
||||
String password = jsonUser.get("password").getAsString();
|
||||
String aeskey = jsonUser.get("aes_key").getAsString();
|
||||
Map<String, File> userFiles = new HashMap<>();
|
||||
JsonArray jsonFiles = jsonUser.getAsJsonArray("files");
|
||||
getFiles(userFiles, jsonFiles);
|
||||
User user = new User(name, password, aeskey, userFiles);
|
||||
users.add(user);
|
||||
}
|
||||
}
|
||||
|
||||
private void getFiles(Map<String, File> userFiles, JsonArray jsonFiles) {
|
||||
for (JsonElement fileElement : jsonFiles) {
|
||||
JsonObject jsonFile = fileElement.getAsJsonObject();
|
||||
String fileName = jsonFile.get("name").getAsString();
|
||||
int size = jsonFile.get("size").getAsInt();
|
||||
String iv = jsonFile.get("iv").getAsString();
|
||||
Set<String> storage = new HashSet<>();
|
||||
JsonArray jsonStorage = jsonFile.getAsJsonArray("storage");
|
||||
getStorage(storage, jsonStorage);
|
||||
File file = new File(fileName, size, iv, storage);
|
||||
userFiles.put(file.getName(), file);
|
||||
}
|
||||
}
|
||||
|
||||
private void getStorage(Set<String> storage, JsonArray jsonStorage) {
|
||||
for (JsonElement storageElement : jsonStorage) {
|
||||
String storageName = storageElement.getAsString();
|
||||
storage.add(storageName);
|
||||
}
|
||||
}
|
||||
}
|
51
app/src/main/java/lightcontainer/storage/Repository.java
Normal file
51
app/src/main/java/lightcontainer/storage/Repository.java
Normal file
@ -0,0 +1,51 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
public class Repository {
|
||||
|
||||
/**
|
||||
* @param filePath The path where the file must be saved
|
||||
* @param adapter The service that converts Objects to Strings
|
||||
*/
|
||||
static void save(String filePath, Adapter adapter) {
|
||||
if (filePath != null) {
|
||||
String jsonAppData = adapter.toString();
|
||||
try (BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(filePath).toAbsolutePath(), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||
bufferedWriter.write(jsonAppData);
|
||||
bufferedWriter.flush();
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error while saving configuration file !");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filePath The path where the file is stored
|
||||
* @param adapter The service that converts Strings to objects
|
||||
* @return
|
||||
*/
|
||||
static AppData load(String filePath, Adapter adapter) {
|
||||
String jsonString = readFile(filePath);
|
||||
return adapter.fromString(jsonString);
|
||||
}
|
||||
|
||||
private static String readFile(String filePath) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try (BufferedReader reader = Files.newBufferedReader(Paths.get(filePath).toAbsolutePath(), StandardCharsets.UTF_8)) {
|
||||
while (reader.ready()) {
|
||||
builder.append(reader.readLine());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error while reading configuration file");
|
||||
builder.setLength(0);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
80
app/src/main/java/lightcontainer/storage/User.java
Normal file
80
app/src/main/java/lightcontainer/storage/User.java
Normal file
@ -0,0 +1,80 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* User represents a user of the system.
|
||||
*
|
||||
* @author Maximilien LEDOUX <m.ledoux@student.helmo.be>
|
||||
* @version 1.0
|
||||
* @since 1.0
|
||||
*/
|
||||
public class User {
|
||||
|
||||
private final String Name;
|
||||
private final String password;
|
||||
private final String aesKey;
|
||||
private final Map<String, File> files;
|
||||
|
||||
public User(String Name, String password, String aesKey, Map<String, File> files) {
|
||||
this.Name = Name;
|
||||
this.password = password;
|
||||
this.aesKey = aesKey;
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return Name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public String getAesKey() {
|
||||
return aesKey;
|
||||
}
|
||||
|
||||
public Iterator<File> fileIterator() {
|
||||
return files.values().iterator();
|
||||
}
|
||||
|
||||
public File getFile(String fileName) {
|
||||
return this.files.get(fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file The file to add.
|
||||
* @return False if a file with the same name already exists. Otherwise, adds the file and returns true.
|
||||
*/
|
||||
public void addFile(File file) {
|
||||
this.files.put(file.getName(), file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param fileName The name of the file to delete.
|
||||
* @return True if the file was deleted. False otherwise.
|
||||
*/
|
||||
public boolean deleteFile(String fileName) {
|
||||
if (this.files.containsKey(fileName)) {
|
||||
this.files.remove(fileName);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param file The file that needs a storage
|
||||
* @param storage The storage name
|
||||
* @return True if the storage was added to the file. False otherwise.
|
||||
*/
|
||||
public boolean addStorage(File file, String storage) {
|
||||
if (this.files.containsKey(file.getName())) {
|
||||
return file.addStorage(storage);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
38
app/src/main/java/lightcontainer/storage/json-example.json
Normal file
38
app/src/main/java/lightcontainer/storage/json-example.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"unicast_port": 32000,
|
||||
"multicast_ip": "224.25.0.1",
|
||||
"multicast_port": 70000,
|
||||
"network_interface": "LALALALA",
|
||||
"tls": false,
|
||||
"users": [
|
||||
{
|
||||
"username": "endmove",
|
||||
"password": "notre-hash",
|
||||
"aes_key": "jkjiezjijfizef8e4864",
|
||||
"files": [
|
||||
{
|
||||
"file_name": "lol.jpeg",
|
||||
"file_size": 15558,
|
||||
"iv": "8d484e8e84 (lié à la méthode de cryptage)",
|
||||
"storage": [
|
||||
"lol.benjamin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file_name": "super-man.png",
|
||||
"file_size": 24457,
|
||||
"iv": "zf4fe84f (lié à la méthode de cryptage)",
|
||||
"storage": [
|
||||
"lol.benjamin"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"username": "michel",
|
||||
"password": "notre-hash du mdp",
|
||||
"aes_key": "fjshufihehehuhuhuehu",
|
||||
"files": []
|
||||
}
|
||||
]
|
||||
}
|
126
app/src/main/java/lightcontainer/utils/AES_GCM.java
Normal file
126
app/src/main/java/lightcontainer/utils/AES_GCM.java
Normal file
@ -0,0 +1,126 @@
|
||||
package lightcontainer.utils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
|
||||
public class AES_GCM {
|
||||
// Constants
|
||||
public static final int AES_KEY_SIZE = 256;
|
||||
public static final int GCM_IV_LENGTH = 16;
|
||||
public static final int GCM_TAG_LENGTH = 16;
|
||||
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
// Text pour test :
|
||||
String plainText = "salut fils de pute";
|
||||
|
||||
String IV = generateIV();
|
||||
String key = generateSecretKey();
|
||||
|
||||
System.out.println("Original Text : " + plainText);
|
||||
|
||||
byte[] cipherText = encrypt(plainText.getBytes(), key, IV);
|
||||
System.out.println("Encrypted Text : " + Base64.getEncoder().encodeToString(cipherText));
|
||||
|
||||
String decryptedText = decrypt(cipherText, key, IV);
|
||||
System.out.println("DeCrypted Text : " + decryptedText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decoder to decode base64 vector to byte vector.
|
||||
* @param base64Vector A base64 encoded vector.
|
||||
* @return Byte vector.
|
||||
*/
|
||||
private static byte[] decodeBase64(String base64Vector) {
|
||||
Base64.Decoder b64Decoder = Base64.getDecoder();
|
||||
return b64Decoder.decode(base64Vector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encoder to encode vector to base64 string.
|
||||
* @param rawVector A raw vector.
|
||||
* @return A base64 encoded vector.
|
||||
*/
|
||||
private static String encodeBase64(byte[] rawVector) {
|
||||
Base64.Encoder b64Encoder = Base64.getEncoder();
|
||||
return b64Encoder.encodeToString(rawVector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secret key base64 encoded.
|
||||
* @return New Secret key b64 encoded.
|
||||
*/
|
||||
public static String generateSecretKey() throws NoSuchAlgorithmException {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
|
||||
keyGenerator.init(AES_KEY_SIZE);
|
||||
SecretKey key = keyGenerator.generateKey();
|
||||
return encodeBase64(key.getEncoded());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an IV (initialisation vector) base64 encoded.
|
||||
* @return New generated IV b64 encoded.
|
||||
*/
|
||||
public static String generateIV() {
|
||||
byte[] IV = new byte[GCM_IV_LENGTH];
|
||||
SecureRandom random = new SecureRandom();
|
||||
random.nextBytes(IV);
|
||||
return encodeBase64(IV);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt, with AES GCM.
|
||||
* @param plainContent Content to encrypt.
|
||||
* @param key Base64 encoded secret key.
|
||||
* @param IV Base64 encoded vector.
|
||||
* @return The encrypted cipherContent.
|
||||
*/
|
||||
public static byte[] encrypt(byte[] plainContent, String key, String IV) throws Exception
|
||||
{
|
||||
// Get Cipher Instance
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
|
||||
// Create SecretKeySpec
|
||||
SecretKeySpec keySpec = new SecretKeySpec(decodeBase64(key), "AES");
|
||||
|
||||
// Create GCMParameterSpec
|
||||
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, decodeBase64(IV));
|
||||
|
||||
// Initialize Cipher for ENCRYPT_MODE
|
||||
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec);
|
||||
|
||||
// Perform Encryption
|
||||
return cipher.doFinal(plainContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt, with AES GCM.
|
||||
* @param cipherContent The encrypted cipherContent
|
||||
* @param key Base64 encoded secret key.
|
||||
* @param IV Base64 encoded vector.
|
||||
* @return The decrypted plainContent.
|
||||
*/
|
||||
public static String decrypt(byte[] cipherContent, String key, String IV) throws Exception
|
||||
{
|
||||
// Get Cipher Instance
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
|
||||
// Create SecretKeySpec
|
||||
SecretKeySpec keySpec = new SecretKeySpec(decodeBase64(key), "AES");
|
||||
|
||||
// Create GCMParameterSpec
|
||||
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH*8, decodeBase64(IV));
|
||||
|
||||
// Initialize Cipher for DECRYPT_MODE
|
||||
cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
|
||||
|
||||
// Perform Decryption
|
||||
return new String(cipher.doFinal(cipherContent));
|
||||
}
|
||||
}
|
37
app/src/main/java/lightcontainer/utils/FileReceiver.java
Normal file
37
app/src/main/java/lightcontainer/utils/FileReceiver.java
Normal file
@ -0,0 +1,37 @@
|
||||
package lightcontainer.utils;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class FileReceiver {
|
||||
private static final int DEFAULT_BUFFER = 8000;
|
||||
private String path;
|
||||
|
||||
public FileReceiver(String path) { this.path = path; }
|
||||
|
||||
public boolean receiveFile(InputStream input, String fileName, long fileSize) {
|
||||
int bytesReceived = 0;
|
||||
BufferedOutputStream bosFile = null;
|
||||
|
||||
try {
|
||||
byte[] buffer = new byte[DEFAULT_BUFFER];
|
||||
bosFile = new BufferedOutputStream(new FileOutputStream(String.format("%s/%s", path, fileName)));
|
||||
long currentOffset = 0;
|
||||
|
||||
while((currentOffset < fileSize) && ((bytesReceived = input.read(buffer)) > 0)) {
|
||||
bosFile.write(buffer, 0, bytesReceived);
|
||||
currentOffset += bytesReceived;
|
||||
}
|
||||
bosFile.flush();
|
||||
bosFile.close();
|
||||
|
||||
return true;
|
||||
} catch(Exception ex) {
|
||||
ex.printStackTrace();
|
||||
if(bosFile != null) { try { bosFile.close(); } catch(Exception e) {} }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
35
app/src/main/java/lightcontainer/utils/FileSender.java
Normal file
35
app/src/main/java/lightcontainer/utils/FileSender.java
Normal file
@ -0,0 +1,35 @@
|
||||
package lightcontainer.utils;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public class FileSender {
|
||||
private static final int DEFAULT_BUFFER=8000;
|
||||
private String path;
|
||||
|
||||
public FileSender(String path) { this.path = path; }
|
||||
|
||||
public boolean sendFile(String filename, OutputStream out) {
|
||||
BufferedInputStream bisFile = null;
|
||||
int bytesReaded = 0;
|
||||
|
||||
try {
|
||||
File f = new File(String.format("%s/%s", path, filename));
|
||||
long fileSize = f.length();
|
||||
if(f.exists()) {
|
||||
byte[] buffer = new byte[DEFAULT_BUFFER];
|
||||
bisFile = new BufferedInputStream(new FileInputStream(f));
|
||||
long currentOffset = 0;
|
||||
while((currentOffset < fileSize) && (bytesReaded = bisFile.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, bytesReaded); out.flush();
|
||||
currentOffset+= bytesReaded;
|
||||
}
|
||||
bisFile.close();
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
} catch(IOException ex) {
|
||||
ex.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
69
app/src/main/java/lightcontainer/utils/NetChooser.java
Normal file
69
app/src/main/java/lightcontainer/utils/NetChooser.java
Normal file
@ -0,0 +1,69 @@
|
||||
package lightcontainer.utils;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class NetChooser {
|
||||
private List<NetworkInterface> interfaces;
|
||||
|
||||
public NetChooser() {
|
||||
loadInterfaces();
|
||||
Scanner console = new Scanner(System.in);
|
||||
String[] allInterfaceNames = getInterfaces();
|
||||
for(int index=0; index < allInterfaceNames.length; ++index) {
|
||||
System.out.printf("%d. %s\n", index, allInterfaceNames[index]);
|
||||
}
|
||||
System.out.printf("Select your interface :");
|
||||
NetworkInterface selected = getInterfacesByIndex(console.nextInt());
|
||||
System.out.printf("Selected interface: %s\n", selected.getDisplayName());
|
||||
|
||||
}
|
||||
|
||||
private void loadInterfaces() {
|
||||
try {
|
||||
interfaces = new ArrayList<>();
|
||||
Enumeration<NetworkInterface> discoveredInterfaces = NetworkInterface.getNetworkInterfaces();
|
||||
while (discoveredInterfaces.hasMoreElements()) {
|
||||
NetworkInterface currentInterface = discoveredInterfaces.nextElement();
|
||||
Enumeration<InetAddress> inetAddresses = currentInterface.getInetAddresses();
|
||||
int ipCount = 0;
|
||||
while(inetAddresses.hasMoreElements()) {
|
||||
InetAddress currentAddress = inetAddresses.nextElement();
|
||||
ipCount++;
|
||||
}
|
||||
if(ipCount > 0)
|
||||
interfaces.add(currentInterface);
|
||||
}
|
||||
} catch(SocketException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public NetworkInterface getInterfacesByIndex(int i) {
|
||||
if(i >= 0)
|
||||
return interfaces.get(i);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public String[] getInterfaces() {
|
||||
if(interfaces.size() > 0) {
|
||||
String[] result = new String[interfaces.size()];
|
||||
for (int i = 0; i < interfaces.size(); ++i) {
|
||||
result[i] = interfaces.get(i).getDisplayName();
|
||||
}
|
||||
return result;
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new NetChooser();
|
||||
}
|
||||
}
|
43
app/src/main/resources/rules.txt
Normal file
43
app/src/main/resources/rules.txt
Normal file
@ -0,0 +1,43 @@
|
||||
//Standardized definitions
|
||||
digit = [0-9]
|
||||
port = (6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4})
|
||||
size = [0-9]{1,10}
|
||||
line = \r\n
|
||||
visiblechar = \p{Print}
|
||||
passchar = [^ !]
|
||||
binary = .
|
||||
password = [^ !]{5,50}
|
||||
bl = //espace
|
||||
letter = [A-Za-z]
|
||||
digit_letter = [A-Za-z0-9]
|
||||
filename = [^ !]{1,20}
|
||||
domain = [A-Za-z0-9.]{5,20}
|
||||
hash_filename = [A-Za-z0-9.]{50,200}
|
||||
hash_filecontent = [A-Za-z0-9.]{50,200}
|
||||
file_info = [A-Za-z0-9.]{50,200} [0-9]{1,10} [A-Za-z0-9.]{50,200}
|
||||
login = [A-Za-z0-9]{2,20}
|
||||
|
||||
//StorBackEnd to FileFrontEnd
|
||||
sbe_hello = ^HELLO ([A-Za-z0-9.]{5,20}) ([\d]{0,5})\r\n$ //TODO \r\n -> à tester pour voir si déjà dans le flux ou doit être construit
|
||||
|
||||
//FileFrontEnd to StorBackEnd
|
||||
ffe_sendfile = ^SENDFILE ([A-Za-z0-9.]{50,200} [0-9]{1,10} [A-Za-z0-9.]{50,200})\r\n$
|
||||
sbe_sendresult = ^(SEND_OK|SEND_ERROR)\r\n$
|
||||
ffe_erasefile = ^ERASEFILE ([A-Za-z0-9.]{50,200})\r\n$
|
||||
sbe_eraseresult = ^(ERASE_OK|ERASE_ERROR)\r\n$
|
||||
ffe_retrievefile = ^RETRIEVEFILE ([A-Za-z0-9.]{50,200})\r\n$
|
||||
sbe_retrieveresult = ^(RETRIEVE_OK ([A-Za-z0-9.]{50,200} [0-9]{1,10} [A-Za-z0-9.]{50,200})\r\n)|(RETRIEVE_ERROR\r\n)$
|
||||
|
||||
//Client to FileFrontEnd
|
||||
client_signin = ^SIGNIN ([A-Za-z0-9]{2,20}) ([^ !]{5,50})\r\n$
|
||||
client_signup = ^SIGNUP ([A-Za-z0-9]{2,20}) ([^ !]{5,50})\r\n$
|
||||
ffe_signresult = ^(SIGN_OK|SIGN_ERROR)\r\n$
|
||||
client_filelist = ^FILELIST\r\n$
|
||||
ffe_filelistresult = ^FILES( ([^ !]{1,20})!([0-9]{1,10})){0,50}$
|
||||
client_savefile = ^SAVE_FILE ([^ !]{1,20}) ([0-9]{1,10})\r\n$
|
||||
ffe_savefileresult = ^(SAVEFILE_OK|SAVEFILE_ERROR)\r\n$
|
||||
client_getfile = ^GETFILE ([^ !]{1,20})\r\n$
|
||||
ffe_getfileresult = ^(GETFILE_OK (^ !]{1,20}) ([0-9]{1,10})\r\n)|(GETFILE_ERROR\r\n)$
|
||||
client_removefile = ^REMOVEFILE ([^ !]{1,20})\r\n$
|
||||
ffe_removefileresult = ^(REMOVEFILE_OK|REMOVEFILE_ERROR)\r\n$
|
||||
client_signout = ^SIGNOUT\r\n$
|
14
app/src/test/java/lightcontainer/AppTest.java
Normal file
14
app/src/test/java/lightcontainer/AppTest.java
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* This Java source file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
package lightcontainer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class AppTest {
|
||||
// @Test void appHasAGreeting() {
|
||||
// App classUnderTest = new App();
|
||||
// assertNotNull(classUnderTest.getGreeting(), "app should have a greeting");
|
||||
// }
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package lightcontainer.protocol.rules.reader;
|
||||
|
||||
import lightcontainer.protocol.ProtocolReader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class HelloRuleTest {
|
||||
|
||||
@Test
|
||||
public void whenRuleIsRightThenIsExecute() {
|
||||
// GIVEN
|
||||
ProtocolReader protocolReader = new HelloRule();
|
||||
String request = "HELLO bento 42890\r\n";
|
||||
|
||||
// WHEN
|
||||
HelloRule.Result ruleResult = protocolReader.execute(request);
|
||||
|
||||
// THEN
|
||||
assertEquals("bento", ruleResult.getDomain());
|
||||
assertEquals(42890, ruleResult.getPort());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package lightcontainer.protocol.rules.writer;
|
||||
|
||||
import lightcontainer.protocol.ProtocolWriter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class SignoutRuleTest {
|
||||
|
||||
@Test
|
||||
public void whenRuleIsRightThenReturnCommand() {
|
||||
//GIVEN
|
||||
ProtocolWriter protocolWriter = new SignoutRule();
|
||||
String[] datas = {};
|
||||
|
||||
//EXPECT
|
||||
assertNotNull(protocolWriter.execute(datas));
|
||||
assertEquals("SIGNOUT\r\n", protocolWriter.execute(datas));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
||||
public class JsonAdapterTests {
|
||||
|
||||
@Test
|
||||
public void convertAppDataToJson() {
|
||||
//GIVEN an AppData instance and a Json Adapter
|
||||
AppData appData = AppData.getInstance();
|
||||
AppConfig appConfig = AppConfig.getInstance();
|
||||
appConfig.setUnicastPort(32000);
|
||||
appConfig.setMulticastIp("224.25.0.1");
|
||||
appConfig.setMulticastPort(15502);
|
||||
appConfig.setNetworkInterface("My network interface");
|
||||
appConfig.setTls(false);
|
||||
Map<String, File> files = new HashMap<>();
|
||||
Set<String> storage = new HashSet<>();
|
||||
storage.add("StorBackEnd1");
|
||||
File file1 = new File("File1", 15, "8d8d8d8d", storage);
|
||||
files.put(file1.getName(), file1);
|
||||
User user1 = new User("User1", "Password", "djdjjdj", files);
|
||||
appData.setAppConfig(appConfig);
|
||||
appData.addUser(user1);
|
||||
JsonAdapter jsonAdapter = new JsonAdapter(appData);
|
||||
//WHEN the adapter converts AppData to Json
|
||||
String jsonAppData = jsonAdapter.toString();
|
||||
//THEN
|
||||
assertTrue(jsonAppData.contains("32000"));
|
||||
assertTrue(jsonAppData.contains("224.25.0.1"));
|
||||
assertTrue(jsonAppData.contains("15502"));
|
||||
assertTrue(jsonAppData.contains("My network interface"));
|
||||
assertTrue(jsonAppData.contains("false"));
|
||||
assertTrue(jsonAppData.contains("User1"));
|
||||
assertTrue(jsonAppData.contains("Password"));
|
||||
assertTrue(jsonAppData.contains("djdjjdj"));
|
||||
assertTrue(jsonAppData.contains("File1"));
|
||||
assertTrue(jsonAppData.contains("15"));
|
||||
assertTrue(jsonAppData.contains("8d8d8d8d"));
|
||||
assertTrue(jsonAppData.contains("StorBackEnd1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertJsonToAppData() {
|
||||
//GIVEN a Json string
|
||||
String json = "{\"unicast_port\":32000,\"multicast_ip\":\"224.25.0.1\",\"multicast_port\":15502,\"network_interface\":\"My network interface\",\"tls\":false,\"users\":[{\"name\":\"User1\",\"password\":\"Password\",\"aes_key\":\"djdjjdj\",\"files\":[{\"name\":\"File1\",\"size\":15,\"iv\":\"8d8d8d8d\",\"storage\":[\"StorBackEnd1\"]}]}]}";
|
||||
//WHEN the adapter converts Json to Appdata
|
||||
JsonAdapter jsonAdapter = new JsonAdapter(null);
|
||||
AppData appData = jsonAdapter.fromString(json);
|
||||
//THEN
|
||||
assertNotNull(appData.getAppConfig());
|
||||
assertEquals("My network interface", appData.getAppConfig().getNetworkInterface());
|
||||
assertEquals(32000, appData.getAppConfig().getUnicastPort());
|
||||
assertEquals("224.25.0.1", appData.getAppConfig().getMulticastIp());
|
||||
assertEquals(15502, appData.getAppConfig().getMulticastPort());
|
||||
assertFalse(appData.getAppConfig().isTls());
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package lightcontainer.storage;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
|
||||
public class RepositoryTests {
|
||||
|
||||
@AfterEach
|
||||
public void destroyTestFile() {
|
||||
try {
|
||||
Files.deleteIfExists(Paths.get("src", "test", "resources", "test.json").toAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error while destroying file");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void save() {
|
||||
//GIVEN an AppData instance and a Json Adapter
|
||||
AppData appData = AppData.getInstance();
|
||||
AppConfig appConfig = AppConfig.getInstance();
|
||||
appConfig.setUnicastPort(32000);
|
||||
appConfig.setMulticastIp("224.25.0.1");
|
||||
appConfig.setMulticastPort(15502);
|
||||
appConfig.setNetworkInterface("My network interface");
|
||||
appConfig.setTls(false);
|
||||
Map<String, File> files = new HashMap<>();
|
||||
Set<String> storage = new HashSet<>();
|
||||
storage.add("StorBackEnd1");
|
||||
File file1 = new File("File1", 15, "8d8d8d8d", storage);
|
||||
files.put(file1.getName(), file1);
|
||||
User user1 = new User("User1", "Password", "djdjjdj", files);
|
||||
appData.setAppConfig(appConfig);
|
||||
appData.addUser(user1);
|
||||
JsonAdapter jsonAdapter = new JsonAdapter(appData);
|
||||
//WHEN Repository calls save method
|
||||
String filePath = "src/test/resources/test.json";
|
||||
Repository.save(filePath, jsonAdapter);
|
||||
//THEN
|
||||
assertTrue(Files.exists(Paths.get("src/test/resources/test.json").toAbsolutePath()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void load() {
|
||||
//GIVEN a test json file loadTest.json
|
||||
JsonAdapter jsonAdapter = new JsonAdapter(null);
|
||||
//WHEN repository calls load method
|
||||
AppData appData = Repository.load("src/test/resources/loadTest.json", jsonAdapter);
|
||||
//THEN
|
||||
assertNotNull(appData.getAppConfig());
|
||||
assertEquals("My network interface", appData.getAppConfig().getNetworkInterface());
|
||||
assertEquals(32000, appData.getAppConfig().getUnicastPort());
|
||||
assertEquals("224.25.0.1", appData.getAppConfig().getMulticastIp());
|
||||
assertEquals(15502, appData.getAppConfig().getMulticastPort());
|
||||
assertFalse(appData.getAppConfig().isTls());
|
||||
}
|
||||
}
|
24
app/src/test/resources/loadTest.json
Normal file
24
app/src/test/resources/loadTest.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"unicast_port": 32000,
|
||||
"multicast_ip": "224.25.0.1",
|
||||
"multicast_port": 15502,
|
||||
"network_interface": "My network interface",
|
||||
"tls": false,
|
||||
"users": [
|
||||
{
|
||||
"name": "User1",
|
||||
"password": "Password",
|
||||
"aes_key": "djdjjdj",
|
||||
"files": [
|
||||
{
|
||||
"name": "File1",
|
||||
"size": 15,
|
||||
"iv": "8d8d8d8d",
|
||||
"storage": [
|
||||
"StorBackEnd1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
2
gradlew
vendored
2
gradlew
vendored
@ -72,7 +72,7 @@ case "`uname`" in
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
|
11
settings.gradle
Normal file
11
settings.gradle
Normal file
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
*
|
||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||
* in the user manual at https://docs.gradle.org/7.1/userguide/multi_project_builds.html
|
||||
*/
|
||||
|
||||
rootProject.name = 'FileFrontEnd'
|
||||
include('app')
|
Loading…
Reference in New Issue
Block a user