mirror of
https://github.com/Akomry/sae302_applicom.git
synced 2025-12-06 03:33:54 +00:00
Merge branch 'dev-event' into 'dev'
feat(event): gestion des événements réseau See merge request iut_rt/but2/sae302-applicom/bouclyma!5
This commit is contained in:
commit
ba6d3afe24
9 changed files with 710 additions and 7 deletions
|
|
@ -3,6 +3,7 @@ package rtgre.chat;
|
|||
import javafx.application.Platform;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.embed.swing.SwingFXUtils;
|
||||
|
|
@ -22,11 +23,13 @@ import javafx.stage.Stage;
|
|||
import net.synedra.validatorfx.Check;
|
||||
import net.synedra.validatorfx.TooltipWrapper;
|
||||
import net.synedra.validatorfx.Validator;
|
||||
import org.json.JSONObject;
|
||||
import rtgre.chat.graphisme.ContactListViewCell;
|
||||
import rtgre.chat.graphisme.PostListViewCell;
|
||||
import rtgre.chat.net.ChatClient;
|
||||
import rtgre.modeles.*;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
|
@ -96,6 +99,7 @@ public class ChatController implements Initializable {
|
|||
avatarMenuItem.setOnAction(this::handleAvatarChange);
|
||||
avatarImageView.setOnMouseClicked(this::handleAvatarChange);
|
||||
sendButton.setOnAction(this::onActionSend);
|
||||
messageTextField.setOnAction(this::onActionSend);
|
||||
|
||||
initContactListView();
|
||||
initPostListView();
|
||||
|
|
@ -108,6 +112,10 @@ public class ChatController implements Initializable {
|
|||
.decorates(loginTextField)
|
||||
.immediate();
|
||||
|
||||
ObservableValue<Boolean> canSendCondition = connectionButton.selectedProperty().not()
|
||||
.or(contactsListView.getSelectionModel().selectedItemProperty().isNull());
|
||||
sendButton.disableProperty().bind(canSendCondition);
|
||||
messageTextField.disableProperty().bind(canSendCondition);
|
||||
|
||||
/* /!\ Set-up d'environnement de test /!\ */
|
||||
/* -------------------------------------- */
|
||||
|
|
@ -120,7 +128,9 @@ public class ChatController implements Initializable {
|
|||
String login = getSelectedContactLogin();
|
||||
if (login != null) {
|
||||
Message message = new Message(login, messageTextField.getText());
|
||||
LOGGER.info(message.toString());
|
||||
LOGGER.info("Sending " + message);
|
||||
client.sendMessageEvent(message);
|
||||
this.messageTextField.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -149,17 +159,22 @@ public class ChatController implements Initializable {
|
|||
contactMap.put(this.contact.getLogin(), this.contact);
|
||||
LOGGER.info("Nouveau contact : " + contact);
|
||||
LOGGER.info(contactMap.toString());
|
||||
Matcher matcher = hostPortPattern.matcher("localhost:2024");
|
||||
Matcher matcher = hostPortPattern.matcher(hostComboBox.getValue());
|
||||
matcher.matches();
|
||||
String host = matcher.group(1);
|
||||
int port = (matcher.group(2) != null) ? Integer.parseInt(matcher.group(2)) : 2024;
|
||||
try {
|
||||
LOGGER.info(host + ":" + port);
|
||||
this.client = new ChatClient(host, port, this);
|
||||
initContactListView();
|
||||
initPostListView();
|
||||
clearLists();
|
||||
contactMap.add(this.contact);
|
||||
this.contact.setConnected(true);
|
||||
|
||||
client.sendAuthEvent(contact);
|
||||
client.sendEvent(new rtgre.modeles.Event(rtgre.modeles.Event.LIST_CONTACTS, new JSONObject()));
|
||||
|
||||
initContactListView();
|
||||
initPostListView();
|
||||
this.statusLabel.setText("Connected to %s@%s:%s".formatted(this.contact.getLogin(), host, port));
|
||||
|
|
@ -168,9 +183,11 @@ public class ChatController implements Initializable {
|
|||
connectionButton.setSelected(false);
|
||||
}
|
||||
} else if (!connectionButton.isSelected()) {
|
||||
this.client.sendQuitEvent();
|
||||
clearLists();
|
||||
this.client.close();
|
||||
this.contact.setConnected(false);
|
||||
if (this.client.isConnected()) {
|
||||
this.contact.setConnected(false);
|
||||
}
|
||||
statusLabel.setText("not connected to " + hostComboBox.getValue());
|
||||
}
|
||||
|
||||
|
|
@ -260,8 +277,55 @@ public class ChatController implements Initializable {
|
|||
if (contactSelected != null) {
|
||||
LOGGER.info("Clic sur " + contactSelected);
|
||||
}
|
||||
Post postSys = new Post("system", contactSelected.getLogin(), "Bienvenue dans la discussion avec " + contactSelected.getLogin());
|
||||
Post postSys = new Post("system", loginTextField.getText(), "Bienvenue dans la discussion avec " + contactSelected.getLogin());
|
||||
postsObservableList.clear();
|
||||
postsObservableList.add(postSys);
|
||||
client.sendListPostEvent(0, contactSelected.getLogin());
|
||||
postListView.refresh();
|
||||
}
|
||||
|
||||
public void handleEvent(rtgre.modeles.Event event) {
|
||||
LOGGER.info("Received new event! : " + event);
|
||||
LOGGER.info(event.getType());
|
||||
if (event.getType().equals("CONT")) {
|
||||
handleContEvent(event.getContent());
|
||||
} else if (event.getType().equals(rtgre.modeles.Event.POST)) {
|
||||
handlePostEvent(event.getContent());
|
||||
} else {
|
||||
LOGGER.warning("Unhandled event type: " + event.getType());
|
||||
this.client.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePostEvent(JSONObject content) {
|
||||
System.out.println(content.getString("to").equals(((Contact) contactsListView.getSelectionModel().getSelectedItem()).getLogin()));
|
||||
if (content.getString("to").equals(((Contact) contactsListView.getSelectionModel().getSelectedItem()).getLogin()) ||
|
||||
content.getString("from").equals(loginTextField.getText())) {
|
||||
postVector.add(Post.fromJson(content));
|
||||
postsObservableList.add(Post.fromJson(content));
|
||||
postListView.refresh();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void handleContEvent(JSONObject content) {
|
||||
Contact contact = contactMap.getContact(content.getString("login"));
|
||||
if (contact != null) {
|
||||
LOGGER.info(contactMap.toString());
|
||||
contactMap.getContact(content.getString("login")).setConnected(content.getBoolean("connected"));
|
||||
contactsListView.refresh();
|
||||
LOGGER.info(contactMap.toString());
|
||||
} else {
|
||||
LOGGER.info(contactMap.toString());
|
||||
Contact user = Contact.fromJSON(
|
||||
content,
|
||||
new File("chat/src/main/resources/rtgre/chat/avatars.png")
|
||||
);
|
||||
System.out.println(user.getAvatar());
|
||||
contactMap.add(user);
|
||||
contactObservableList.add(user);
|
||||
LOGGER.info(contactMap.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,8 +1,15 @@
|
|||
package rtgre.chat.net;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import org.json.JSONObject;
|
||||
import rtgre.chat.ChatController;
|
||||
import rtgre.modeles.Contact;
|
||||
import rtgre.modeles.Event;
|
||||
import rtgre.modeles.Message;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static rtgre.chat.ChatApplication.LOGGER;
|
||||
|
|
@ -26,6 +33,47 @@ public class ChatClient extends ClientTCP {
|
|||
this.listener = listener;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void sendEvent(Event event) {
|
||||
connected = true;
|
||||
try {
|
||||
String message = event.toJson();
|
||||
if (message == null) { // fin du flux stdIn
|
||||
message = END_MESSAGE;
|
||||
}
|
||||
System.out.println(BLUE + "Envoi: " + message + RST);
|
||||
this.send(message);
|
||||
if (END_MESSAGE.equals(message)) {
|
||||
connected = false;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.severe(e.toString());
|
||||
connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void sendAuthEvent(Contact contact) {
|
||||
Event authEvent = new Event(Event.AUTH, new JSONObject().put("login", contact.getLogin()));
|
||||
sendEvent(authEvent);
|
||||
}
|
||||
|
||||
public void sendListPostEvent(long since, String select) {
|
||||
Event listPostEvent = new Event(
|
||||
Event.LIST_POSTS,
|
||||
new JSONObject()
|
||||
.put("since", since)
|
||||
.put("select", select)
|
||||
);
|
||||
sendEvent(listPostEvent);
|
||||
}
|
||||
|
||||
public void sendQuitEvent() {
|
||||
Event quitEvent = new Event(Event.QUIT, new JSONObject());
|
||||
sendEvent(quitEvent);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receiveLoop() {
|
||||
LOGGER.info(RED + "Boucle de réception de messages..." + RST);
|
||||
|
|
@ -34,6 +82,9 @@ public class ChatClient extends ClientTCP {
|
|||
String message = this.receive();
|
||||
LOGGER.info(RED + "Réception: " + message + RST);
|
||||
LOGGER.info(RED + message + RST);
|
||||
if (listener != null) {
|
||||
Platform.runLater(() -> listener.handleEvent(Event.fromJson(message)));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.severe("[%s] %s".formatted(ipPort, e));
|
||||
|
|
@ -50,4 +101,8 @@ public class ChatClient extends ClientTCP {
|
|||
public ChatController getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
public void sendMessageEvent(Message msg) {
|
||||
sendEvent(new Event("MESG", msg.toJsonObject()));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package rtgre.modeles;
|
||||
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
|
|
@ -101,6 +103,20 @@ public class Contact {
|
|||
return 0;
|
||||
}
|
||||
|
||||
public JSONObject toJsonObject() {
|
||||
return new JSONObject()
|
||||
.put("login", this.login)
|
||||
.put("connected", this.connected);
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return toJsonObject().toString();
|
||||
}
|
||||
|
||||
public static Contact fromJSON(JSONObject jsonObject, File banque_avatars) {
|
||||
return new Contact(jsonObject.getString("login"), jsonObject.getBoolean("connected"), banque_avatars);
|
||||
}
|
||||
|
||||
public static BufferedImage avatarFromLogin(File fichier, String login) throws IOException {
|
||||
/**
|
||||
* Renvoie une sous-image en fonction d'une banque d'image et d'un login.
|
||||
|
|
|
|||
|
|
@ -9,4 +9,16 @@ public class ContactMap extends TreeMap<String, Contact> {
|
|||
public Contact getContact(String login) {
|
||||
return this.get(login);
|
||||
}
|
||||
|
||||
public void loadDefaultContacts() {
|
||||
this.put("mickey", new Contact("mickey", null));
|
||||
this.put("minnie", new Contact("minnie", null));
|
||||
this.put("dingo", new Contact("dingo", null));
|
||||
this.put("riri", new Contact("riri", null));
|
||||
this.put("fifi", new Contact("fifi", null));
|
||||
this.put("loulou", new Contact("loulou", null));
|
||||
this.put("donald", new Contact("donald", null));
|
||||
this.put("daisy", new Contact("daisy", null));
|
||||
this.put("picsou", new Contact("picsou", null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
52
chat/src/main/java/rtgre/modeles/Event.java
Normal file
52
chat/src/main/java/rtgre/modeles/Event.java
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package rtgre.modeles;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class Event {
|
||||
public static final String AUTH = "AUTH";
|
||||
public static final String QUIT = "QUIT";
|
||||
public static final String MESG = "MESG";
|
||||
public static final String JOIN = "JOIN";
|
||||
public static final String POST = "POST";
|
||||
public static final String CONT = "CONT";
|
||||
public static final String LIST_CONTACTS = "LSTC";
|
||||
public static final String LIST_POSTS = "LSTP";
|
||||
public static final String SYSTEM = "SYST";
|
||||
private final String type;
|
||||
private final JSONObject content;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public JSONObject getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public Event(String type, JSONObject content) {
|
||||
this.type = type;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Event{type=" + type + ", content=" + content.toString() + "}";
|
||||
}
|
||||
|
||||
public JSONObject toJsonObject() {
|
||||
return new JSONObject().put("type", type).put("content", content);
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return toJsonObject().toString();
|
||||
}
|
||||
|
||||
public static Event fromJson(String json) throws JSONException {
|
||||
JSONObject jsonObject = new JSONObject(json);
|
||||
String type = jsonObject.getString("type");
|
||||
JSONObject content = jsonObject.getJSONObject("content");
|
||||
return new Event(type, content);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,5 +1,10 @@
|
|||
package rtgre.server;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import rtgre.chat.net.ChatClient;
|
||||
import rtgre.modeles.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
|
@ -17,6 +22,8 @@ public class ChatServer {
|
|||
private static final Logger LOGGER = Logger.getLogger(ChatServer.class.getCanonicalName());
|
||||
|
||||
private Vector<ChatClientHandler> clientList;
|
||||
private PostVector postVector;
|
||||
private ContactMap contactMap;
|
||||
|
||||
static {
|
||||
try {
|
||||
|
|
@ -31,6 +38,7 @@ public class ChatServer {
|
|||
|
||||
public static void main(String[] args) throws IOException {
|
||||
ChatServer server = new ChatServer(2024);
|
||||
daisyConnect();
|
||||
server.acceptClients();
|
||||
}
|
||||
|
||||
|
|
@ -43,6 +51,9 @@ public class ChatServer {
|
|||
passiveSock = new ServerSocket(port);
|
||||
LOGGER.info("Serveur en écoute " + passiveSock);
|
||||
clientList = new Vector<>();
|
||||
contactMap = new ContactMap();
|
||||
postVector = new PostVector();
|
||||
contactMap.loadDefaultContacts();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
|
|
@ -93,7 +104,7 @@ public class ChatServer {
|
|||
*/
|
||||
private void handleNewClient(Socket sock) throws IOException {
|
||||
ChatClientHandler client = new ChatClientHandler(sock);
|
||||
Thread clientLoop = new Thread(client::echoLoop);
|
||||
Thread clientLoop = new Thread(client::eventReceiveLoop);
|
||||
clientLoop.start();
|
||||
clientList.add(client);
|
||||
LOGGER.fine("Ajout du client [%s] dans la liste (%d clients connectés)"
|
||||
|
|
@ -101,6 +112,45 @@ public class ChatServer {
|
|||
//client.echoLoop();
|
||||
}
|
||||
|
||||
public ChatClientHandler findClient(Contact contact) {
|
||||
for (ChatClientHandler user: clientList) {
|
||||
if (user.user.equals(contact)) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void sendEventToContact(Contact contact, Event event) {
|
||||
ChatClientHandler user = findClient(contact);
|
||||
if (!(user == null)) {
|
||||
try {
|
||||
user.send(event.toJson());
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("!!Erreur de l'envoi d'Event à %s, fermeture de la connexion".formatted(user.user.getLogin()));
|
||||
user.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendEventToAllContacts(Event event) {
|
||||
for (Contact contact: contactMap.values()) {
|
||||
if (contact.isConnected()) {
|
||||
sendEventToContact(contact, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ContactMap getContactMap() {
|
||||
return contactMap;
|
||||
}
|
||||
|
||||
/** Temporaire : connecte daisy pour test */
|
||||
public static void daisyConnect() throws IOException {
|
||||
ChatClient client = new ChatClient("localhost", 2024, null);
|
||||
client.sendAuthEvent(new Contact("daisy", null));
|
||||
}
|
||||
|
||||
private class ChatClientHandler {
|
||||
public static final String END_MESSAGE = "fin";
|
||||
/**
|
||||
|
|
@ -120,6 +170,8 @@ public class ChatServer {
|
|||
*/
|
||||
private String ipPort;
|
||||
|
||||
private Contact user;
|
||||
|
||||
/**
|
||||
* Initialise les attributs {@link #sock} (socket connecté au client),
|
||||
* {@link #out} (flux de caractères UTF-8 en sortie) et
|
||||
|
|
@ -160,6 +212,123 @@ public class ChatServer {
|
|||
close();
|
||||
}
|
||||
|
||||
public void eventReceiveLoop() {
|
||||
try {
|
||||
String message = null;
|
||||
while (!END_MESSAGE.equals(message)) {
|
||||
message = in.readLine();
|
||||
if (message == null) {
|
||||
break;
|
||||
}
|
||||
LOGGER.info("[%s] Réception de : %s".formatted(ipPort, message));
|
||||
try {
|
||||
if (!handleEvent(message)) {
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(e.getMessage());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOGGER.severe("[%s] %s".formatted(ipPort, e));
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
private boolean handleEvent(String message) throws JSONException, IllegalStateException {
|
||||
Event event = Event.fromJson(message);
|
||||
if (event.getType().equals(Event.AUTH)) {
|
||||
doLogin(event.getContent());
|
||||
LOGGER.finest("Login successful");
|
||||
return true;
|
||||
} else if (event.getType().equals(Event.LIST_CONTACTS)) {
|
||||
doListContact(event.getContent());
|
||||
LOGGER.finest("Sending contacts");
|
||||
return true;
|
||||
} else if (event.getType().equals(Event.MESG)) {
|
||||
doMessage(event.getContent());
|
||||
LOGGER.info("Receiving message");
|
||||
return true;
|
||||
} else if (event.getType().equals(Event.LIST_POSTS)) {
|
||||
doListPost(event.getContent());
|
||||
LOGGER.info("Sending Posts");
|
||||
return true;
|
||||
} else if (event.getType().equals(Event.QUIT)) {
|
||||
LOGGER.info("Déconnexion");
|
||||
return false;
|
||||
} else {
|
||||
LOGGER.warning("Unhandled event type: " + event.getType());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void doListPost(JSONObject content) throws JSONException, IllegalStateException {
|
||||
|
||||
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
||||
if (!contactMap.containsKey(content.getString("select"))) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
for (Post post: postVector.getPostsSince(content.getLong("since"))) {
|
||||
if (post.getTo().equals(content.getString("select")) ||
|
||||
post.getFrom().equals(content.getString("select"))) {
|
||||
sendEventToContact(contactMap.getContact(user.getLogin()), new Event(Event.POST, post.toJsonObject()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doMessage(JSONObject content) throws JSONException, IllegalStateException {
|
||||
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
||||
if (content.getString("to").equals(user.getLogin()) || !contactMap.containsKey(content.getString("to"))) {
|
||||
throw new IllegalStateException();
|
||||
} else {
|
||||
Post post = new Post(
|
||||
user.getLogin(),
|
||||
Message.fromJson(content)
|
||||
);
|
||||
Event postEvent = new Event("POST", post.toJsonObject());
|
||||
|
||||
sendEventToContact(contactMap.getContact(post.getFrom()), postEvent);
|
||||
sendEventToContact(contactMap.getContact(post.getTo()), postEvent);
|
||||
|
||||
postVector.add(post);
|
||||
LOGGER.info("Fin de doMessage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doListContact(JSONObject content) throws JSONException, IllegalStateException {
|
||||
for (Contact contact: contactMap.values()) {
|
||||
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
||||
try {
|
||||
send(new Event(Event.CONT, contact.toJsonObject()).toJson());
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doLogin(JSONObject content) {
|
||||
String login = content.getString("login");
|
||||
if (login.isEmpty()) {
|
||||
LOGGER.warning("Aucun login fourni");
|
||||
throw new JSONException("Aucun login fourni");
|
||||
} else if (!contactMap.containsKey(login)) {
|
||||
LOGGER.warning("Login non-authorisé");
|
||||
throw new IllegalStateException("Login non-authorisé");
|
||||
} else {
|
||||
LOGGER.info("Connexion de " + login);
|
||||
contactMap.getContact(login).setConnected(true);
|
||||
this.user = contactMap.getContact(login);
|
||||
sendAllOtherClients(
|
||||
findClient(contactMap.getContact(login)),
|
||||
new Event("CONT", user.toJsonObject()).toJson()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void send(String message) throws IOException {
|
||||
LOGGER.finest("send: %s".formatted(message));
|
||||
out.println(message);
|
||||
|
|
@ -189,7 +358,7 @@ public class ChatServer {
|
|||
|
||||
public String receive() throws IOException {
|
||||
String message = in.readLine();
|
||||
LOGGER.finest("receive: %s".formatted(message));
|
||||
LOGGER.info("receive: %s".formatted(message));
|
||||
if (message == null) {
|
||||
throw new IOException("End of the stream has been reached");
|
||||
}
|
||||
|
|
@ -201,6 +370,8 @@ public class ChatServer {
|
|||
try {
|
||||
sock.close();
|
||||
removeClient(this);
|
||||
user.setConnected(false);
|
||||
sendEventToAllContacts(new Event(Event.CONT, user.toJsonObject()));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
|||
BIN
chat/src/main/resources/rtgre/chat/banque_avatars.png
Normal file
BIN
chat/src/main/resources/rtgre/chat/banque_avatars.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
110
chat/src/test/java/rtgre/modeles/ContactWithEventTest3.java
Normal file
110
chat/src/test/java/rtgre/modeles/ContactWithEventTest3.java
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
package rtgre.modeles;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
/** Tests unitaires du modèle de base de Contact (étape 1) */
|
||||
|
||||
class ContactWithEventTest3 {
|
||||
|
||||
static Class<?> classe = Contact.class;
|
||||
static String module = "rtgre.modeles";
|
||||
|
||||
@DisplayName("01-Structure de la classe Contact")
|
||||
@Nested
|
||||
class StructureTest {
|
||||
|
||||
static List<String> constructeursSignatures;
|
||||
static List<String> methodesSignatures;
|
||||
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
Constructor<?>[] constructeurs = classe.getConstructors();
|
||||
constructeursSignatures = Arrays.stream(constructeurs).map(Constructor::toString).collect(Collectors.toList());
|
||||
Method[] methodes = classe.getDeclaredMethods();
|
||||
methodesSignatures = Arrays.stream(methodes).map(Method::toString).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static Stream<Arguments> methodesProvider3() {
|
||||
return Stream.of(
|
||||
arguments("toJsonObject", "public org.json.JSONObject %s.Contact.toJsonObject()"),
|
||||
arguments("toJson", "public java.lang.String %s.Contact.toJson()"),
|
||||
arguments("fromJSON", "public static %s.Contact %s.Contact.fromJSON(org.json.JSONObject,java.io.File)")
|
||||
);
|
||||
}
|
||||
// @Disabled("Jusqu'à ce que soit codé les events")
|
||||
@DisplayName("Déclaration des méthodes (avec event et JSON)")
|
||||
@ParameterizedTest
|
||||
@MethodSource("methodesProvider3")
|
||||
void testDeclarationMethodes3(String nom, String signature) {
|
||||
Assertions.assertTrue(methodesSignatures.contains(String.format(signature, module, module)),
|
||||
String.format("Méthode non déclarée : doit être %s\nalors que sont déclarés %s",
|
||||
signature, methodesSignatures));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@DisplayName("07-Représentation JSON")
|
||||
@Nested
|
||||
class JSONTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("JSONObject")
|
||||
void TestToJSONObject() {
|
||||
String erreur = "Représentation JSON erronée";
|
||||
Contact fifi = new Contact("fifi", true, (Image) null);
|
||||
JSONObject json = fifi.toJsonObject();
|
||||
Assertions.assertTrue(json.has("login"), erreur);
|
||||
Assertions.assertEquals("fifi", json.get("login"), erreur);
|
||||
Assertions.assertTrue(json.has("connected"), erreur);
|
||||
Assertions.assertEquals(true, json.get("connected"), erreur);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Sérialisation JSON")
|
||||
void TestToJSON() {
|
||||
String erreur = "Sérialisation de la représentation JSON erronée";
|
||||
Contact riri = new Contact("riri", true, (Image) null);
|
||||
String json = riri.toJson();
|
||||
Assertions.assertTrue(json.contains("\"login\":\"riri\""), erreur);
|
||||
Assertions.assertTrue(json.contains("\"connected\":true"), erreur);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Contact à partir d'un JSON")
|
||||
void TestConstructeur() throws IOException {
|
||||
String work_dir = System.getProperty("user.dir");
|
||||
Assertions.assertTrue(work_dir.endsWith("chat"),
|
||||
"Le working dir doit être <projet>/chat/ et non : " + work_dir);
|
||||
File f = new File("src/main/resources/rtgre/chat/banque_avatars.png");
|
||||
String json = "{\"login\":\"riri\",\"connected\":true}";
|
||||
Contact toto = Contact.fromJSON(new JSONObject(json), f);
|
||||
Assertions.assertEquals("riri", toto.getLogin(), "Login erroné");
|
||||
Assertions.assertEquals(true, toto.isConnected(), "Connected erroné");
|
||||
Assertions.assertNotNull(toto.getAvatar(), "Avatar non chargé");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
223
chat/src/test/java/rtgre/modeles/EventTest.java
Normal file
223
chat/src/test/java/rtgre/modeles/EventTest.java
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
package rtgre.modeles;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
|
||||
class EventTest {
|
||||
|
||||
static Class<?> classe = Event.class;
|
||||
static String module = "rtgre.modeles";
|
||||
|
||||
// @Tag("01-mise_en_place_contact")
|
||||
@DisplayName("01-Structure de Event")
|
||||
@Nested
|
||||
class StructureTest {
|
||||
|
||||
static List<String> constructeursSignatures;
|
||||
static List<String> methodesSignatures;
|
||||
|
||||
@BeforeAll
|
||||
static void init() {
|
||||
Constructor<?>[] constructeurs = classe.getConstructors();
|
||||
constructeursSignatures = Arrays.stream(constructeurs).map(Constructor::toString).collect(Collectors.toList());
|
||||
Method[] methodes = classe.getDeclaredMethods();
|
||||
methodesSignatures = Arrays.stream(methodes).map(Method::toString).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
static Stream<Arguments> constantesProvider() {
|
||||
return Stream.of(
|
||||
arguments("AUTH", "AUTH"),
|
||||
arguments("QUIT", "QUIT"),
|
||||
arguments("MESG", "MESG"),
|
||||
arguments("JOIN", "JOIN"),
|
||||
arguments("POST", "POST"),
|
||||
arguments("CONT", "CONT"),
|
||||
arguments("LIST_POSTS", "LSTP"),
|
||||
arguments("LIST_CONTACTS", "LSTC"),
|
||||
arguments("SYSTEM", "SYST")
|
||||
);
|
||||
}
|
||||
|
||||
@DisplayName("Déclaration des constantes")
|
||||
@ParameterizedTest
|
||||
@MethodSource("constantesProvider")
|
||||
void testDeclarationConstantes(String constante, String value) throws NoSuchFieldException, IllegalAccessException {
|
||||
Field field = classe.getField(constante);
|
||||
Assertions.assertEquals(Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC, field.getModifiers(),
|
||||
"Visibilité " + constante + " erronée");
|
||||
Assertions.assertEquals("java.lang.String", field.getType().getName(),
|
||||
"Type " + constante + " erroné");
|
||||
Assertions.assertEquals(value, field.get(null), "Valeur " + constante + " erronée");
|
||||
}
|
||||
|
||||
|
||||
static Stream<Arguments> attributsProvider() {
|
||||
return Stream.of(
|
||||
arguments("type", "java.lang.String", Modifier.PRIVATE | Modifier.FINAL),
|
||||
arguments("content", "org.json.JSONObject", Modifier.PRIVATE | Modifier.FINAL)
|
||||
);
|
||||
}
|
||||
|
||||
@DisplayName("Déclaration des attributs")
|
||||
@ParameterizedTest
|
||||
@MethodSource("attributsProvider")
|
||||
void testDeclarationAttributs(String nom, String type, int modifier) throws NoSuchFieldException {
|
||||
Field field = classe.getDeclaredField(nom);
|
||||
Assertions.assertEquals(type, field.getType().getName(),
|
||||
"Type " + nom + " erroné : doit être " + type);
|
||||
Assertions.assertEquals(modifier, field.getModifiers(),
|
||||
"Visibilité " + nom + " erronée : doit être " + modifier);
|
||||
|
||||
}
|
||||
|
||||
static Stream<Arguments> constructeursProvider() {
|
||||
return Stream.of(
|
||||
arguments("public %s.Event(java.lang.String,org.json.JSONObject)")
|
||||
);
|
||||
}
|
||||
|
||||
@DisplayName("Déclaration des constructeurs")
|
||||
@ParameterizedTest
|
||||
@MethodSource("constructeursProvider")
|
||||
void testConstructeurs1(String signature) {
|
||||
Assertions.assertTrue(constructeursSignatures.contains(String.format(signature, module)),
|
||||
String.format("Constructeur non déclaré : doit être %s\nalors que sont déclarés %s",
|
||||
signature, constructeursSignatures));
|
||||
|
||||
}
|
||||
|
||||
static Stream<Arguments> methodesProvider() {
|
||||
return Stream.of(
|
||||
arguments("getType", "public java.lang.String %s.Event.getType()"),
|
||||
arguments("getContent", "public org.json.JSONObject %s.Event.getContent()"),
|
||||
arguments("toString", "public java.lang.String %s.Event.toString()"),
|
||||
arguments("toJsonObject", "public org.json.JSONObject %s.Event.toJsonObject()"),
|
||||
arguments("toJson", "public java.lang.String %s.Event.toJson()"),
|
||||
arguments("fromJson", "public static %s.Event %s.Event.fromJson(java.lang.String) throws org.json.JSONException")
|
||||
);
|
||||
}
|
||||
|
||||
@DisplayName("Déclaration des méthodes")
|
||||
@ParameterizedTest
|
||||
@MethodSource("methodesProvider")
|
||||
void testDeclarationMethodes1(String nom, String signature) {
|
||||
Assertions.assertTrue(methodesSignatures.contains(String.format(signature, module, module)),
|
||||
String.format("Méthode non déclarée : doit être %s\nalors que sont déclarés %s",
|
||||
signature, methodesSignatures));
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("02-Instanciation d'un évènement")
|
||||
@Nested
|
||||
class InstanciationTest {
|
||||
|
||||
@Test
|
||||
@DisplayName("Constructeur par défaut")
|
||||
void TestContructeurParDefaut() {
|
||||
JSONObject json = new JSONObject("{\"login\":\"riri\"}");
|
||||
Event event = new Event("AUTH", json);
|
||||
Assertions.assertEquals("AUTH", event.getType(), "Type erroné");
|
||||
Assertions.assertEquals(json, event.getContent(), "Content erroné");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@DisplayName("03-Instanciation fromJSON")
|
||||
@Nested
|
||||
class fromJSONTest {
|
||||
|
||||
static Stream<Arguments> contentProvides() {
|
||||
return Stream.of(
|
||||
arguments("AUTH", "{\"type\":\"AUTH\",\"content\":{\"login\":\"riri\"}}"),
|
||||
arguments("QUIT", "{\"type\": \"QUIT\",\"content\": {}}"),
|
||||
arguments("MESG", "{\"type\": \"MESG\",\"content\": {\"to\":\"DEST\",\"body\":\"BODY\"}}")
|
||||
);
|
||||
}
|
||||
@DisplayName("Récupération du type")
|
||||
@ParameterizedTest
|
||||
@MethodSource("contentProvides")
|
||||
void TestContructeurType(String type, String json) {
|
||||
Event event = Event.fromJson(json);
|
||||
Assertions.assertEquals(type, event.getType(), "Type erroné");
|
||||
}
|
||||
|
||||
static Stream<Arguments> keyProvides() {
|
||||
return Stream.of(
|
||||
arguments("login", "riri", "{\"type\":\"AUTH\",\"content\":{\"login\":\"riri\"}}"),
|
||||
arguments("to", "DEST", "{\"type\": \"MESG\",\"content\": {\"to\":\"DEST\",\"body\":\"BODY\"}}"),
|
||||
arguments("body", "BODY", "{\"type\": \"MESG\",\"content\": {\"to\":\"DEST\",\"body\":\"BODY\"}}")
|
||||
);
|
||||
}
|
||||
|
||||
@DisplayName("Récupération du contenu")
|
||||
@ParameterizedTest
|
||||
@MethodSource("keyProvides")
|
||||
void TestContructeurContenu(String key, String value, String json) {
|
||||
Event event = Event.fromJson(json);
|
||||
Assertions.assertTrue(event.getContent().has(key), "Contenu erroné");
|
||||
Assertions.assertEquals(value, event.getContent().get(key), "Contenu erroné");
|
||||
}
|
||||
|
||||
@DisplayName("Levée d'exception")
|
||||
@Test
|
||||
void TestFromJsonException() {
|
||||
assertThrows(JSONException.class, () -> Event.fromJson("bonjour"));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("04-Méthodes")
|
||||
|
||||
class TestMethodes {
|
||||
@Test
|
||||
@DisplayName("Méthode toString")
|
||||
void TestToString() {
|
||||
Event event = Event.fromJson("{\"type\":\"AUTH\",\"content\":{\"login\":\"riri\"}}");
|
||||
String repr = event.toString();
|
||||
Assertions.assertEquals("Event{type=AUTH, content={\"login\":\"riri\"}}", repr, "Représentation textuelle erronée");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Méthode toJsonObject")
|
||||
void TestToJsonObject() {
|
||||
Event event = Event.fromJson("{\"type\":\"AUTH\",\"content\":{\"login\":\"riri\"}}");
|
||||
JSONObject json = event.toJsonObject();
|
||||
Assertions.assertTrue(json.has("type"), "Représentation JSON erronée");
|
||||
Assertions.assertEquals("AUTH", json.get("type"), "Représentation JSON erronée");
|
||||
Assertions.assertTrue(json.has("content"), "Représentation JSON erronée");
|
||||
Assertions.assertTrue(json.getJSONObject("content").has("login"), "Représentation JSON erronée");
|
||||
Assertions.assertEquals("riri", json.getJSONObject("content").get("login"), "Représentation JSON erronée");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Méthode toJson")
|
||||
void TestToJson() {
|
||||
Event event = Event.fromJson("{\"type\":\"AUTH\",\"content\":{\"login\":\"riri\"}}");
|
||||
String json = event.toJson();
|
||||
Assertions.assertEquals("{\"type\":\"AUTH\",\"content\":{\"login\":\"riri\"}}",
|
||||
json, "Sérialisation JSON erronée");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue