mirror of
https://github.com/Akomry/sae302_applicom.git
synced 2025-12-06 08:43:54 +00:00
Merge branch 'dev-doc' into 'dev'
doc: ajout de la javadoc sur toutes les classes See merge request iut_rt/but2/sae302-applicom/bouclyma!16
This commit is contained in:
commit
ddba5f8c39
21 changed files with 920 additions and 93 deletions
|
|
@ -5,7 +5,14 @@ import rtgre.server.ChatServer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application pour lancer soit ChatServer, soit ChatApplication
|
||||||
|
*/
|
||||||
public class ChatLauncher {
|
public class ChatLauncher {
|
||||||
|
/**
|
||||||
|
* Avec le paramètre "server" sur la ligne de commande, ChatServer, sinon lance ChatApplication
|
||||||
|
* @param args Paramètres de la ligne de commande
|
||||||
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
System.out.println(arg);
|
System.out.println(arg);
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,15 @@ import java.util.logging.Level;
|
||||||
import java.util.logging.LogManager;
|
import java.util.logging.LogManager;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application graphique de chat
|
||||||
|
*/
|
||||||
public class ChatApplication extends Application {
|
public class ChatApplication extends Application {
|
||||||
|
/** Logger de l'application graphique */
|
||||||
public static final Logger LOGGER = Logger.getLogger(ChatApplication.class.getCanonicalName());
|
public static final Logger LOGGER = Logger.getLogger(ChatApplication.class.getCanonicalName());
|
||||||
|
/** Controller de l'application de chat */
|
||||||
private ChatController controller;
|
private ChatController controller;
|
||||||
|
/** Stage principal */
|
||||||
private Stage stage;
|
private Stage stage;
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
|
|
@ -33,6 +39,11 @@ public class ChatApplication extends Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lancement de l'application
|
||||||
|
* @param stage La scène graphique
|
||||||
|
* @throws IOException En cas de problème d'accès aux ressources
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) throws IOException {
|
public void start(Stage stage) throws IOException {
|
||||||
ResourceBundle i18nBundle = ResourceBundle.getBundle("rtgre.chat.i18nBundle",
|
ResourceBundle i18nBundle = ResourceBundle.getBundle("rtgre.chat.i18nBundle",
|
||||||
|
|
@ -67,6 +78,9 @@ public class ChatApplication extends Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fermeture de l'application
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void stop() {
|
public void stop() {
|
||||||
try {
|
try {
|
||||||
|
|
@ -86,6 +100,10 @@ public class ChatApplication extends Application {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Programme principal
|
||||||
|
* @param args Les arguments du programme principal
|
||||||
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch();
|
launch();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,45 +49,84 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static rtgre.chat.ChatApplication.LOGGER;
|
import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller de l'application de chat
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class ChatController implements Initializable {
|
public class ChatController implements Initializable {
|
||||||
|
|
||||||
|
/** Pattern associé à une regex pour vérifier si le login est correct */
|
||||||
private static final Pattern LOGIN_PATTERN = Pattern.compile("^([a-z][a-z0-9]{2,7})$");
|
private static final Pattern LOGIN_PATTERN = Pattern.compile("^([a-z][a-z0-9]{2,7})$");
|
||||||
private static final Pattern HOST_PATTERN = Pattern.compile("/^[a-z]*((\\:?)\\d{1,5})?$/gm");
|
/** Pattern associé à une regex pour récupérer le nom d'hôte et du port à partir d'un socket */
|
||||||
private final Pattern hostPortPattern = Pattern.compile("^([-.a-zA-Z0-9]+)(?::([0-9]{1,5}))?$");
|
private final Pattern hostPortPattern = Pattern.compile("^([-.a-zA-Z0-9]+)(?::([0-9]{1,5}))?$");
|
||||||
|
/** Menu `Add Host` */
|
||||||
public MenuItem hostAddMenuItem;
|
public MenuItem hostAddMenuItem;
|
||||||
|
/** Menu `Change avatar` */
|
||||||
public MenuItem avatarMenuItem;
|
public MenuItem avatarMenuItem;
|
||||||
|
/** Menu `About` */
|
||||||
public MenuItem aboutMenuItem;
|
public MenuItem aboutMenuItem;
|
||||||
|
/** Liste déroulante des serveurs disponibles */
|
||||||
public ComboBox<String> hostComboBox;
|
public ComboBox<String> hostComboBox;
|
||||||
|
/** Zone de saisie du login */
|
||||||
public TextField loginTextField;
|
public TextField loginTextField;
|
||||||
|
/** Bouton de connexion */
|
||||||
public ToggleButton connectionButton;
|
public ToggleButton connectionButton;
|
||||||
|
/** ImageView de l'avatar */
|
||||||
public ImageView avatarImageView;
|
public ImageView avatarImageView;
|
||||||
|
/** Séparateur des messages/destainataires */
|
||||||
public SplitPane exchangeSplitPane;
|
public SplitPane exchangeSplitPane;
|
||||||
|
/** Vue des messages */
|
||||||
public ListView<Post> postListView;
|
public ListView<Post> postListView;
|
||||||
|
/** Vue des salons */
|
||||||
public ListView<Room> roomsListView;
|
public ListView<Room> roomsListView;
|
||||||
|
/** Vue des contacts */
|
||||||
public ListView<Contact> contactsListView;
|
public ListView<Contact> contactsListView;
|
||||||
|
/** Zone de saisie du message */
|
||||||
public TextField messageTextField;
|
public TextField messageTextField;
|
||||||
|
/** Bouton d'envoi du message */
|
||||||
public Button sendButton;
|
public Button sendButton;
|
||||||
|
/** Statut */
|
||||||
public Label statusLabel;
|
public Label statusLabel;
|
||||||
|
/** Horodatage */
|
||||||
public Label dateTimeLabel;
|
public Label dateTimeLabel;
|
||||||
|
/** Contact associé à l'utilisateur courant */
|
||||||
public Contact contact;
|
public Contact contact;
|
||||||
|
/** Séparateur des salons/contacts */
|
||||||
public SplitPane senderSplitPane;
|
public SplitPane senderSplitPane;
|
||||||
|
/** Annuaire des contacts */
|
||||||
private ContactMap contactMap = new ContactMap();
|
private ContactMap contactMap = new ContactMap();
|
||||||
|
/** Liste observable associée aux contacts */
|
||||||
private ObservableList<Contact> contactObservableList = FXCollections.observableArrayList();
|
private ObservableList<Contact> contactObservableList = FXCollections.observableArrayList();
|
||||||
|
/** Liste observable associée aux messages */
|
||||||
private ObservableList<Post> postsObservableList = FXCollections.observableArrayList();
|
private ObservableList<Post> postsObservableList = FXCollections.observableArrayList();
|
||||||
|
/** Instance de validateur permettant de vérifier la validité du login à partir du pattern LOGIN_PATTERN */
|
||||||
private Validator validatorLogin = new Validator();
|
private Validator validatorLogin = new Validator();
|
||||||
|
/** Client de connexion */
|
||||||
private ChatClient client = null;
|
private ChatClient client = null;
|
||||||
|
/** Liste des messages */
|
||||||
private PostVector postVector;
|
private PostVector postVector;
|
||||||
|
/** Liste des salons */
|
||||||
private RoomMap roomMap = new RoomMap();
|
private RoomMap roomMap = new RoomMap();
|
||||||
|
/** Liste observable associée aux salons */
|
||||||
private ObservableList<Room> roomObservableList = FXCollections.observableArrayList();
|
private ObservableList<Room> roomObservableList = FXCollections.observableArrayList();
|
||||||
|
/** ResourceBundle contenant les textes en fonction des langues */
|
||||||
private ResourceBundle i18nBundle;
|
private ResourceBundle i18nBundle;
|
||||||
|
/** Propriétés chargées à partir d'un fichier `config.properties` */
|
||||||
private Properties properties = new Properties();
|
private Properties properties = new Properties();
|
||||||
private Vector<String> hostlist;
|
/** Menu contextuel associé à un clic droit sur un message */
|
||||||
private ContextMenu contextMenu = new ContextMenu();
|
private ContextMenu contextMenu = new ContextMenu();
|
||||||
|
/** Menu `removeItem` */
|
||||||
private MenuItem removeMenuItem;
|
private MenuItem removeMenuItem;
|
||||||
|
/** Menu `editMenuItem` */
|
||||||
private MenuItem editMenuItem;
|
private MenuItem editMenuItem;
|
||||||
|
/** Menu `cancelMenuItem` */
|
||||||
private MenuItem cancelMenuItem;
|
private MenuItem cancelMenuItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialisation du composant graphique
|
||||||
|
* @param url L'url
|
||||||
|
* @param resourceBundle Le ResourceBundle contenant les textes relatifs aux langues
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
LOGGER.info("Initialisation de l'interface graphique");
|
LOGGER.info("Initialisation de l'interface graphique");
|
||||||
|
|
@ -173,12 +212,21 @@ public class ChatController implements Initializable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Affiche le menu contextuel lors d'un clic droit sur un message dans la PostListView
|
||||||
|
*
|
||||||
|
* @param e L'évènement associé à un clic droit sur la PostListView
|
||||||
|
*/
|
||||||
private void handleContextMenu(ContextMenuEvent e) {
|
private void handleContextMenu(ContextMenuEvent e) {
|
||||||
if (postListView.getSelectionModel().getSelectedItem().getFrom().equals(contact.getLogin())) {
|
if (postListView.getSelectionModel().getSelectedItem().getFrom().equals(contact.getLogin())) {
|
||||||
contextMenu.show(postListView, e.getScreenX(), e.getScreenY());
|
contextMenu.show(postListView, e.getScreenX(), e.getScreenY());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise le menu de contexte lors d'un clic droit sur un message dans la PostListView
|
||||||
|
*
|
||||||
|
*/
|
||||||
private void initContextMenu() {
|
private void initContextMenu() {
|
||||||
this.removeMenuItem = new MenuItem();
|
this.removeMenuItem = new MenuItem();
|
||||||
this.editMenuItem = new MenuItem();
|
this.editMenuItem = new MenuItem();
|
||||||
|
|
@ -195,6 +243,13 @@ public class ChatController implements Initializable {
|
||||||
contextMenu.getItems().addAll(removeMenuItem, editMenuItem, cancelMenuItem);
|
contextMenu.getItems().addAll(removeMenuItem, editMenuItem, cancelMenuItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime le message sélectionné par le menu contextuel, affiche une vue de modification du message, puis envoie
|
||||||
|
* un événement POST associé au nouveau message.
|
||||||
|
* Conserve l'`UUID`, le `timestamp`, les champs `from` et `to`
|
||||||
|
* @param actionEvent L'évènement lié au bouton "Edit message" dans le menu
|
||||||
|
*/
|
||||||
private void onMessageEdit(ActionEvent actionEvent) {
|
private void onMessageEdit(ActionEvent actionEvent) {
|
||||||
UUID postUUID = postListView.getSelectionModel().getSelectedItem().getId();
|
UUID postUUID = postListView.getSelectionModel().getSelectedItem().getId();
|
||||||
long timestamp = postListView.getSelectionModel().getSelectedItem().getTimestamp();
|
long timestamp = postListView.getSelectionModel().getSelectedItem().getTimestamp();
|
||||||
|
|
@ -214,6 +269,12 @@ public class ChatController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supprime le message sélectionné par le menu contextuel, et envoie un nouvel évènement POST associé au message
|
||||||
|
* de remplacement
|
||||||
|
* Conserve l'`UUID`, le `timestamp`, les champs `from` et `to`
|
||||||
|
* @param actionEvent L'évènement lié au bouton "Delete message" dans le menu
|
||||||
|
*/
|
||||||
private void onMessageRemove(ActionEvent actionEvent) {
|
private void onMessageRemove(ActionEvent actionEvent) {
|
||||||
UUID postUUID = postListView.getSelectionModel().getSelectedItem().getId();
|
UUID postUUID = postListView.getSelectionModel().getSelectedItem().getId();
|
||||||
long timestamp = postListView.getSelectionModel().getSelectedItem().getTimestamp();
|
long timestamp = postListView.getSelectionModel().getSelectedItem().getTimestamp();
|
||||||
|
|
@ -225,6 +286,10 @@ public class ChatController implements Initializable {
|
||||||
postListView.refresh();
|
postListView.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ouvre une fenêtre de dialogue permettant d'ajouter un hôte à la liste des serveurs.
|
||||||
|
* @param actionEvent L'évènement lié au bouton "Add Host" dans le menu
|
||||||
|
*/
|
||||||
private void handleHostAdd(ActionEvent actionEvent) {
|
private void handleHostAdd(ActionEvent actionEvent) {
|
||||||
try {
|
try {
|
||||||
ChatHostAddController controller = showNewStage(i18nBundle.getString("addHost"), "chathostadd-view.fxml");
|
ChatHostAddController controller = showNewStage(i18nBundle.getString("addHost"), "chathostadd-view.fxml");
|
||||||
|
|
@ -260,6 +325,9 @@ public class ChatController implements Initializable {
|
||||||
return fxmlLoader.getController();
|
return fxmlLoader.getController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise RoomListView avec sa CelFactory et sa liste observable
|
||||||
|
*/
|
||||||
private void initRoomListView() {
|
private void initRoomListView() {
|
||||||
try {
|
try {
|
||||||
roomsListView.setCellFactory(roomListView -> new RoomListViewCell());
|
roomsListView.setCellFactory(roomListView -> new RoomListViewCell());
|
||||||
|
|
@ -269,6 +337,10 @@ public class ChatController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie au serveur un message à destination du contact sélectionné, contenant le texte du champ éditable des messages
|
||||||
|
* @param actionEvent L'évènement lié au bouton Send ou à l'appui sur `Entrée` dans le champ éditable des messages
|
||||||
|
*/
|
||||||
private void onActionSend(ActionEvent actionEvent) {
|
private void onActionSend(ActionEvent actionEvent) {
|
||||||
String login = null;
|
String login = null;
|
||||||
if (!(getSelectedContactLogin() == null)) {
|
if (!(getSelectedContactLogin() == null)) {
|
||||||
|
|
@ -284,10 +356,11 @@ public class ChatController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ouvre une fenêtre de dialogue permettant de choisir son avatar à partir d'un fichier image
|
||||||
|
* @param event L'évènement lié au clic sur l'avatar ou sur le bouton `"Change avatar"` dans le menu
|
||||||
|
*/
|
||||||
private void handleAvatarChange(Event event) {
|
private void handleAvatarChange(Event event) {
|
||||||
/**
|
|
||||||
* Ouvre une fenêtre de dialogue permettant de choisir son avatar
|
|
||||||
*/
|
|
||||||
try {
|
try {
|
||||||
FileChooser fileChooser = new FileChooser();
|
FileChooser fileChooser = new FileChooser();
|
||||||
Stage stage = (Stage) avatarImageView.getScene().getWindow();
|
Stage stage = (Stage) avatarImageView.getScene().getWindow();
|
||||||
|
|
@ -315,7 +388,10 @@ public class ChatController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connexion au serveur
|
||||||
|
* @param observable L'évènement lié au clic sur le bouton Connexion/Déconnexion
|
||||||
|
*/
|
||||||
private void handleConnection(Observable observable) {
|
private void handleConnection(Observable observable) {
|
||||||
if (connectionButton.isSelected()) {
|
if (connectionButton.isSelected()) {
|
||||||
java.awt.Image img = SwingFXUtils.fromFXImage(this.avatarImageView.getImage(), null);
|
java.awt.Image img = SwingFXUtils.fromFXImage(this.avatarImageView.getImage(), null);
|
||||||
|
|
@ -367,6 +443,9 @@ public class ChatController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vide toutes les maps, les vecteurs et les listes observables.
|
||||||
|
*/
|
||||||
private void clearLists() {
|
private void clearLists() {
|
||||||
this.contactMap = new ContactMap();
|
this.contactMap = new ContactMap();
|
||||||
this.postVector = new PostVector();
|
this.postVector = new PostVector();
|
||||||
|
|
@ -376,6 +455,10 @@ public class ChatController implements Initializable {
|
||||||
roomObservableList.clear();
|
roomObservableList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si le login est conforme ou s'il n'est pas égal à `"system"`
|
||||||
|
* @param context Le contexte de vérification
|
||||||
|
*/
|
||||||
private void checkLogin(Check.Context context) {
|
private void checkLogin(Check.Context context) {
|
||||||
String login = context.get("login");
|
String login = context.get("login");
|
||||||
if (!LOGIN_PATTERN.matcher(login).matches()) {
|
if (!LOGIN_PATTERN.matcher(login).matches()) {
|
||||||
|
|
@ -388,6 +471,11 @@ public class ChatController implements Initializable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour le label de statut situé en bas à gauche de l'application en fonction de si
|
||||||
|
* l'utilisateur est connecté à un serveur, et si oui, son login et le socket de connexion du serveur
|
||||||
|
* @param event L'évènement lié à l'interaction avec la HostComboBox
|
||||||
|
*/
|
||||||
private void statusNameUpdate(Event event) {
|
private void statusNameUpdate(Event event) {
|
||||||
statusLabel.setText("not connected to " + hostComboBox.getValue());
|
statusLabel.setText("not connected to " + hostComboBox.getValue());
|
||||||
|
|
||||||
|
|
@ -399,7 +487,10 @@ public class ChatController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gestion de l'horloge : affichage de la date courante toutes les secondes dans le label dateTimeLabel`
|
||||||
|
*
|
||||||
|
*/
|
||||||
private void dateTimeLoop() {
|
private void dateTimeLoop() {
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -413,6 +504,9 @@ public class ChatController implements Initializable {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise la CellFactory et la liste observable associée à la ContactListView
|
||||||
|
*/
|
||||||
private void initContactListView() {
|
private void initContactListView() {
|
||||||
try {
|
try {
|
||||||
contactsListView.setCellFactory(contactListView -> new ContactListViewCell());
|
contactsListView.setCellFactory(contactListView -> new ContactListViewCell());
|
||||||
|
|
@ -425,6 +519,10 @@ public class ChatController implements Initializable {
|
||||||
LOGGER.severe(e.getMessage());
|
LOGGER.severe(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise la CellFactory et la liste observable associée à la PostListView
|
||||||
|
*/
|
||||||
private void initPostListView() {
|
private void initPostListView() {
|
||||||
try {
|
try {
|
||||||
postListView.setCellFactory(postListView -> new PostListViewCell(this));
|
postListView.setCellFactory(postListView -> new PostListViewCell(this));
|
||||||
|
|
@ -434,7 +532,10 @@ public class ChatController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le contact sélectionné dans la ListView
|
||||||
|
* @return Le login associé au contact
|
||||||
|
*/
|
||||||
public String getSelectedContactLogin() {
|
public String getSelectedContactLogin() {
|
||||||
Contact contact;
|
Contact contact;
|
||||||
String login;
|
String login;
|
||||||
|
|
@ -448,6 +549,10 @@ public class ChatController implements Initializable {
|
||||||
return login;
|
return login;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le salon sélectionné dans la ListView
|
||||||
|
* @return Le nom du salon
|
||||||
|
*/
|
||||||
public String getSelectedRoomName() {
|
public String getSelectedRoomName() {
|
||||||
Room room;
|
Room room;
|
||||||
String roomName;
|
String roomName;
|
||||||
|
|
@ -461,14 +566,27 @@ public class ChatController implements Initializable {
|
||||||
return roomName;
|
return roomName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le contact utilisant l'application
|
||||||
|
*
|
||||||
|
* @return Le contact
|
||||||
|
*/
|
||||||
public Contact getContact() {
|
public Contact getContact() {
|
||||||
return contact;
|
return contact;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de l'annuaire des contacts
|
||||||
|
* @return L'annuaire des contacts
|
||||||
|
*/
|
||||||
public ContactMap getContactsMap() {
|
public ContactMap getContactsMap() {
|
||||||
return contactMap;
|
return contactMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vide la vue des messages puis envoie un évènement JOIN et un évènement LSTP en fonction du salon sélectionné
|
||||||
|
* @param roomSelected Le salon sélectionné
|
||||||
|
*/
|
||||||
void handleRoomSelection(Room roomSelected) {
|
void handleRoomSelection(Room roomSelected) {
|
||||||
|
|
||||||
if (roomSelected != null) {
|
if (roomSelected != null) {
|
||||||
|
|
@ -491,6 +609,10 @@ public class ChatController implements Initializable {
|
||||||
postListView.refresh();
|
postListView.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vide la vue des messages puis envoie un évènement LSTP en fonction du contact sélectionné
|
||||||
|
* @param contactSelected Le contact sélectionné
|
||||||
|
*/
|
||||||
void handleContactSelection(Contact contactSelected) {
|
void handleContactSelection(Contact contactSelected) {
|
||||||
if (contactSelected != null) {
|
if (contactSelected != null) {
|
||||||
LOGGER.info("Clic sur " + contactSelected);
|
LOGGER.info("Clic sur " + contactSelected);
|
||||||
|
|
@ -509,6 +631,11 @@ public class ChatController implements Initializable {
|
||||||
postListView.refresh();
|
postListView.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback gérant les évènements réseaux reçus en provenance du serveur, en fonction du type de l'évènement
|
||||||
|
* @param event L'évènement reçu
|
||||||
|
*/
|
||||||
public void handleEvent(rtgre.modeles.Event event) {
|
public void handleEvent(rtgre.modeles.Event event) {
|
||||||
LOGGER.info("Received new event! : " + event);
|
LOGGER.info("Received new event! : " + event);
|
||||||
LOGGER.info(event.getType());
|
LOGGER.info(event.getType());
|
||||||
|
|
@ -524,6 +651,10 @@ public class ChatController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traite les évènements de type "CONT" informant de l'état d'un contact
|
||||||
|
* @param content Le contenu d'un évènement `"CONT"`
|
||||||
|
*/
|
||||||
private void handleRoomEvent(JSONObject content) {
|
private void handleRoomEvent(JSONObject content) {
|
||||||
LOGGER.info(content.toString());
|
LOGGER.info(content.toString());
|
||||||
Room room = new Room(content.getString("room"));
|
Room room = new Room(content.getString("room"));
|
||||||
|
|
@ -532,6 +663,10 @@ public class ChatController implements Initializable {
|
||||||
roomsListView.refresh();
|
roomsListView.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traite la réception d'un post
|
||||||
|
* @param content Le contenu d'un évènement `"POST"`
|
||||||
|
*/
|
||||||
private void handlePostEvent(JSONObject content) {
|
private void handlePostEvent(JSONObject content) {
|
||||||
|
|
||||||
System.out.println("Selected: " + roomsListView.getSelectionModel().getSelectedItem());
|
System.out.println("Selected: " + roomsListView.getSelectionModel().getSelectedItem());
|
||||||
|
|
@ -606,6 +741,12 @@ public class ChatController implements Initializable {
|
||||||
postListView.refresh();
|
postListView.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Traite les évènements de type "CONT" informant de l'état d'un contact
|
||||||
|
* @param content Le contenu d'un évènement `"CONT"`
|
||||||
|
*/
|
||||||
private void handleContEvent(JSONObject content) {
|
private void handleContEvent(JSONObject content) {
|
||||||
Contact contact = contactMap.getContact(content.getString("login"));
|
Contact contact = contactMap.getContact(content.getString("login"));
|
||||||
java.awt.Image avatar = null;
|
java.awt.Image avatar = null;
|
||||||
|
|
|
||||||
|
|
@ -16,18 +16,33 @@ import java.util.ResourceBundle;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface graphique permettant à l'utilisateur de choisir un serveur (hote:port) sur lequel il se souhaite se connecter.
|
||||||
|
*/
|
||||||
public class ChatHostAddController implements Initializable {
|
public class ChatHostAddController implements Initializable {
|
||||||
|
|
||||||
|
/** Le champ de saisie de l'hôte */
|
||||||
public TextField hostTextField;
|
public TextField hostTextField;
|
||||||
|
/** Bouton de réinitialisation du camp de saisie */
|
||||||
public Button resetButton;
|
public Button resetButton;
|
||||||
|
/** Wrapper du bouton Submit */
|
||||||
public HBox submitWrapper;
|
public HBox submitWrapper;
|
||||||
|
/** Bouton Submit */
|
||||||
public Button submitButton;
|
public Button submitButton;
|
||||||
|
/** Si la vue possède une valeur de retour */
|
||||||
private boolean ok = false;
|
private boolean ok = false;
|
||||||
|
/** Le pattern à satisfaire par un serveur `hote:port` */
|
||||||
public static final Pattern HOST_PORT_REGEX = Pattern.compile("^([-.a-zA-Z0-9]+)(?::([0-9]{1,5}))?$");
|
public static final Pattern HOST_PORT_REGEX = Pattern.compile("^([-.a-zA-Z0-9]+)(?::([0-9]{1,5}))?$");
|
||||||
|
/** Objet Validator permettant de vérifier la validité d'un serveur `hote:port` */
|
||||||
private Validator validatorHost = new Validator();
|
private Validator validatorHost = new Validator();
|
||||||
|
/** ResourceBundle contenant les textes relatifs aux langues */
|
||||||
private ResourceBundle i18nBundle;
|
private ResourceBundle i18nBundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialisation du composant graphique
|
||||||
|
* @param url L'url
|
||||||
|
* @param resourceBundle Le ResourceBundle contenant les textes relatifs aux langues
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
submitButton.setOnAction(this::onActionSubmit);
|
submitButton.setOnAction(this::onActionSubmit);
|
||||||
|
|
@ -49,6 +64,10 @@ public class ChatHostAddController implements Initializable {
|
||||||
.immediate();
|
.immediate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie si la valeur de `hostTextField` est conforme.
|
||||||
|
* @param context Le contexte de vérification
|
||||||
|
*/
|
||||||
private void checkHost(Check.Context context) {
|
private void checkHost(Check.Context context) {
|
||||||
String host = context.get("host");
|
String host = context.get("host");
|
||||||
if (!HOST_PORT_REGEX.matcher(host).matches()) {
|
if (!HOST_PORT_REGEX.matcher(host).matches()) {
|
||||||
|
|
@ -56,15 +75,29 @@ public class ChatHostAddController implements Initializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback sur le bouton `Reset`
|
||||||
|
* Efface le contenu saisi dans le champ `hostTextField`
|
||||||
|
* @param actionEvent L'évènement associé au clic sur le bouton Reset
|
||||||
|
*/
|
||||||
private void onActionReset(ActionEvent actionEvent) {
|
private void onActionReset(ActionEvent actionEvent) {
|
||||||
hostTextField.setText("");
|
hostTextField.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback sur le bouton `Add`
|
||||||
|
* Ferme la fenêtre pour revenir dans l'application graphique appelante.
|
||||||
|
* @param actionEvent L'évènement associé au clic sur le bouton Add
|
||||||
|
*/
|
||||||
private void onActionSubmit(ActionEvent actionEvent) {
|
private void onActionSubmit(ActionEvent actionEvent) {
|
||||||
ok = true;
|
ok = true;
|
||||||
((Stage) submitButton.getScene().getWindow()).close();
|
((Stage) submitButton.getScene().getWindow()).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du mode de fermeture de la fenêtre
|
||||||
|
* @return la fermeture s'est-elle finie par un clic sur le bouton Send ?
|
||||||
|
*/
|
||||||
public boolean isOk() {
|
public boolean isOk() {
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,26 @@ import javafx.stage.Stage;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface graphique permettant à l'utilisateur de modifier un message.
|
||||||
|
*/
|
||||||
public class ModifyMessageController implements Initializable {
|
public class ModifyMessageController implements Initializable {
|
||||||
|
|
||||||
|
/** Le champ de saisie de l'hôte */
|
||||||
public TextField hostTextField;
|
public TextField hostTextField;
|
||||||
|
/** Bouton de réinitialisation du camp de saisie */
|
||||||
public Button resetButton;
|
public Button resetButton;
|
||||||
|
/** Bouton Submit */
|
||||||
public Button submitButton;
|
public Button submitButton;
|
||||||
|
/** Si la vue possède une valeur de retour */
|
||||||
private Boolean ok;
|
private Boolean ok;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialisation du composant graphique
|
||||||
|
* @param url L'url
|
||||||
|
* @param resourceBundle Le ResourceBundle contenant les textes relatifs aux langues
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
public void initialize(URL url, ResourceBundle resourceBundle) {
|
||||||
resetButton.setOnAction(this::onActionReset);
|
resetButton.setOnAction(this::onActionReset);
|
||||||
|
|
@ -24,15 +36,29 @@ public class ModifyMessageController implements Initializable {
|
||||||
hostTextField.setOnAction(this::onActionSubmit);
|
hostTextField.setOnAction(this::onActionSubmit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback sur le bouton `Reset`
|
||||||
|
* Efface le contenu saisi dans le champ `hostTextField`
|
||||||
|
* @param actionEvent L'évènement associé au clic sur le bouton Reset
|
||||||
|
*/
|
||||||
private void onActionReset(ActionEvent actionEvent) {
|
private void onActionReset(ActionEvent actionEvent) {
|
||||||
hostTextField.setText("");
|
hostTextField.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback sur le bouton `Add`
|
||||||
|
* Ferme la fenêtre pour revenir dans l'application graphique appelante.
|
||||||
|
* @param actionEvent L'évènement associé au clic sur le bouton Add
|
||||||
|
*/
|
||||||
private void onActionSubmit(ActionEvent actionEvent) {
|
private void onActionSubmit(ActionEvent actionEvent) {
|
||||||
ok = true;
|
ok = true;
|
||||||
((Stage) submitButton.getScene().getWindow()).close();
|
((Stage) submitButton.getScene().getWindow()).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du mode de fermeture de la fenêtre
|
||||||
|
* @return la fermeture s'est-elle finie par un clic sur le bouton Send ?
|
||||||
|
*/
|
||||||
public boolean isOk() {
|
public boolean isOk() {
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ public class ContactListViewCell extends ListCell<Contact> {
|
||||||
* Callback déclenchée à chaque modification d'un objet d'une liste d'observable.
|
* Callback déclenchée à chaque modification d'un objet d'une liste d'observable.
|
||||||
*
|
*
|
||||||
* @param contact Le contact à mettre à jour
|
* @param contact Le contact à mettre à jour
|
||||||
* @param empty La liste de cellule doit-elle être complètement remise à zéro ?
|
* @param empty La liste de cellule doit-elle être complètement remise à zéro ?
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(Contact contact, boolean empty) {
|
protected void updateItem(Contact contact, boolean empty) {
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,21 @@ import rtgre.modeles.Post;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant la fabrique de cellule de la vue des posts
|
||||||
|
* {@link ChatController#postListView}.
|
||||||
|
*
|
||||||
|
* @see ListCell
|
||||||
|
*/
|
||||||
public class PostListViewCell extends ListCell<Post> {
|
public class PostListViewCell extends ListCell<Post> {
|
||||||
|
|
||||||
/** Controller de l'application */
|
/** Controller de l'application */
|
||||||
ChatController controller;
|
ChatController controller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur par défaut
|
||||||
|
* @param controller Le controller de l'application grapihque
|
||||||
|
*/
|
||||||
public PostListViewCell(ChatController controller) {
|
public PostListViewCell(ChatController controller) {
|
||||||
this.controller = controller;
|
this.controller = controller;
|
||||||
}
|
}
|
||||||
|
|
@ -28,7 +38,7 @@ public class PostListViewCell extends ListCell<Post> {
|
||||||
* Callback déclenchée à chaque modification d'un objet d'une liste d'observable.
|
* Callback déclenchée à chaque modification d'un objet d'une liste d'observable.
|
||||||
*
|
*
|
||||||
* @param post Le post
|
* @param post Le post
|
||||||
* @param empty La liste de cellule doit-elle être complètement remise à zéro ?
|
* @param empty La liste de cellule doit-elle être complètement remise à zéro ?
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(Post post, boolean empty) {
|
protected void updateItem(Post post, boolean empty) {
|
||||||
|
|
@ -41,6 +51,11 @@ public class PostListViewCell extends ListCell<Post> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mise à jour de la cellule d'un post.
|
||||||
|
*
|
||||||
|
* @param post Le post à mettre à jour
|
||||||
|
*/
|
||||||
void updatePost(Post post) {
|
void updatePost(Post post) {
|
||||||
|
|
||||||
Text datetimeText = new Text("\n%1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS\n".formatted(new Date(post.getTimestamp())));
|
Text datetimeText = new Text("\n%1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS\n".formatted(new Date(post.getTimestamp())));
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import javafx.scene.shape.Rectangle;
|
||||||
import javafx.scene.text.Font;
|
import javafx.scene.text.Font;
|
||||||
import javafx.scene.text.Text;
|
import javafx.scene.text.Text;
|
||||||
import javafx.scene.text.TextAlignment;
|
import javafx.scene.text.TextAlignment;
|
||||||
|
import rtgre.chat.ChatController;
|
||||||
import rtgre.modeles.Contact;
|
import rtgre.modeles.Contact;
|
||||||
import rtgre.modeles.Room;
|
import rtgre.modeles.Room;
|
||||||
|
|
||||||
|
|
@ -21,8 +22,20 @@ import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import static rtgre.chat.ChatApplication.LOGGER;
|
import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant la fabrique de cellule de la vue des salons
|
||||||
|
* {@link ChatController#roomsListView}.
|
||||||
|
*
|
||||||
|
* @see ListCell
|
||||||
|
*/
|
||||||
public class RoomListViewCell extends ListCell<Room> {
|
public class RoomListViewCell extends ListCell<Room> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback déclenchée à chaque modification d'un objet d'une liste d'observable.
|
||||||
|
*
|
||||||
|
* @param room Le salon
|
||||||
|
* @param empty La liste de cellule doit-elle être complètement remise à zéro ?
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void updateItem(Room room, boolean empty) {
|
protected void updateItem(Room room, boolean empty) {
|
||||||
super.updateItem(room, empty);
|
super.updateItem(room, empty);
|
||||||
|
|
@ -36,6 +49,11 @@ public class RoomListViewCell extends ListCell<Room> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Couleur d'un salon, choisie parmi une banque de couleurs, en fonction d'un nom de salon.
|
||||||
|
* @param roomName Nom du salon
|
||||||
|
* @return La couleur associée à la première lettre du nom du salon
|
||||||
|
*/
|
||||||
public Color colorFromName(String roomName) {
|
public Color colorFromName(String roomName) {
|
||||||
switch (roomName) {
|
switch (roomName) {
|
||||||
case "#all":
|
case "#all":
|
||||||
|
|
@ -51,6 +69,11 @@ public class RoomListViewCell extends ListCell<Room> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mise à jour de la cellule d'un salon.
|
||||||
|
*
|
||||||
|
* @param room Le salon à mettre à jour
|
||||||
|
*/
|
||||||
private void updateRoom(Room room) {
|
private void updateRoom(Room room) {
|
||||||
LOGGER.finest("Mise à jour de " + room);
|
LOGGER.finest("Mise à jour de " + room);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,12 @@ import java.util.logging.Logger;
|
||||||
|
|
||||||
import static rtgre.chat.ChatApplication.LOGGER;
|
import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant
|
||||||
|
*/
|
||||||
public class ChatClient extends ClientTCP {
|
public class ChatClient extends ClientTCP {
|
||||||
|
|
||||||
|
/** Le Controller du chat associé à la connexion */
|
||||||
private final ChatController listener;
|
private final ChatController listener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -27,7 +31,7 @@ public class ChatClient extends ClientTCP {
|
||||||
* @param host IP ou nom de domaine du serveur
|
* @param host IP ou nom de domaine du serveur
|
||||||
* @param port port d'écoute du serveur
|
* @param port port d'écoute du serveur
|
||||||
* @param listener instance de ChatController liée au client
|
* @param listener instance de ChatController liée au client
|
||||||
* @throws IOException
|
* @throws IOException si la connexion échoue
|
||||||
*/
|
*/
|
||||||
public ChatClient(String host, int port, ChatController listener) throws IOException {
|
public ChatClient(String host, int port, ChatController listener) throws IOException {
|
||||||
super(host, port);
|
super(host, port);
|
||||||
|
|
@ -35,7 +39,10 @@ public class ChatClient extends ClientTCP {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi d'un évènement, sérialisé dans sa représentation JSON, au serveur.
|
||||||
|
* @param event L'évènement à envoyer
|
||||||
|
*/
|
||||||
public void sendEvent(Event event) {
|
public void sendEvent(Event event) {
|
||||||
connected = true;
|
connected = true;
|
||||||
try {
|
try {
|
||||||
|
|
@ -54,11 +61,20 @@ public class ChatClient extends ClientTCP {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi de l'évènement d'authentification
|
||||||
|
* @param contact Le contact associé à l'utilisateur
|
||||||
|
*/
|
||||||
public void sendAuthEvent(Contact contact) {
|
public void sendAuthEvent(Contact contact) {
|
||||||
Event authEvent = new Event(Event.AUTH, new JSONObject().put("login", contact.getLogin()));
|
Event authEvent = new Event(Event.AUTH, new JSONObject().put("login", contact.getLogin()));
|
||||||
sendEvent(authEvent);
|
sendEvent(authEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demande la liste des posts (évènement de type "LSTP")
|
||||||
|
* @param since L'horodatage à partir duquel est demandée la liste des posts
|
||||||
|
* @param select Le login du contact ou le salon de discussion avec lequel les posts ont été échangés
|
||||||
|
*/
|
||||||
public void sendListPostEvent(long since, String select) {
|
public void sendListPostEvent(long since, String select) {
|
||||||
Event listPostEvent = new Event(
|
Event listPostEvent = new Event(
|
||||||
Event.LIST_POSTS,
|
Event.LIST_POSTS,
|
||||||
|
|
@ -69,17 +85,27 @@ public class ChatClient extends ClientTCP {
|
||||||
sendEvent(listPostEvent);
|
sendEvent(listPostEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demande la liste des salons (évènement de type "LSTR")
|
||||||
|
*/
|
||||||
public void sendListRoomEvent() {
|
public void sendListRoomEvent() {
|
||||||
Event listRoomEvent = new Event(Event.LIST_ROOMS, new JSONObject());
|
Event listRoomEvent = new Event(Event.LIST_ROOMS, new JSONObject());
|
||||||
sendEvent(listRoomEvent);
|
sendEvent(listRoomEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie un évènement de fermeture de connexion (de type "QUIT")
|
||||||
|
*/
|
||||||
public void sendQuitEvent() {
|
public void sendQuitEvent() {
|
||||||
Event quitEvent = new Event(Event.QUIT, new JSONObject());
|
Event quitEvent = new Event(Event.QUIT, new JSONObject());
|
||||||
sendEvent(quitEvent);
|
sendEvent(quitEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boucle de réception des messages : chaque message est un évènement sérialisé en JSON, qui est transféré à ChatController.handleEvent(rtgre.modeles.Event) pour traitement.
|
||||||
|
* Si le message n'est pas conforme (format JSON), la connection est stoppée.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void receiveLoop() {
|
public void receiveLoop() {
|
||||||
LOGGER.info(RED + "Boucle de réception de messages..." + RST);
|
LOGGER.info(RED + "Boucle de réception de messages..." + RST);
|
||||||
|
|
@ -102,18 +128,34 @@ public class ChatClient extends ClientTCP {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du logger
|
||||||
|
* @return Le logger utilisé par ChatClient
|
||||||
|
*/
|
||||||
public Logger getLogger() {
|
public Logger getLogger() {
|
||||||
return LOGGER;
|
return LOGGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du listener
|
||||||
|
* @return Le controller associé à la connexion
|
||||||
|
*/
|
||||||
public ChatController getListener() {
|
public ChatController getListener() {
|
||||||
return listener;
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi d'un message au travers d'un évènement "MSG", contenant l'objet `Message` adressé à un destinataire `to` avec un contenu `body`
|
||||||
|
* @param msg Le message à envoyer
|
||||||
|
*/
|
||||||
public void sendMessageEvent(Message msg) {
|
public void sendMessageEvent(Message msg) {
|
||||||
sendEvent(new Event("MESG", msg.toJsonObject()));
|
sendEvent(new Event("MESG", msg.toJsonObject()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi d'un post au travers d'un évènement "POST".
|
||||||
|
* @param selectedItem Post à envoyer
|
||||||
|
*/
|
||||||
public void sendPostEvent(Post selectedItem) {
|
public void sendPostEvent(Post selectedItem) {
|
||||||
Event postEvent = new Event(Event.POST, selectedItem.toJsonObject());
|
Event postEvent = new Event(Event.POST, selectedItem.toJsonObject());
|
||||||
sendEvent(postEvent);
|
sendEvent(postEvent);
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,43 @@ import java.util.logging.LogManager;
|
||||||
import static rtgre.chat.ChatApplication.LOGGER;
|
import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client TCP: envoie des chaines de caractères à un serveur et lit les chaines en retour.
|
* Client TCP : envoie des chaines de caractères à un serveur et lit les chaines en retour.
|
||||||
* <p>
|
|
||||||
* Serveur netcat à lancer en face : <code>nc -k -l -p 2024 -v</code>
|
|
||||||
*/
|
*/
|
||||||
public class ClientTCP {
|
public class ClientTCP {
|
||||||
|
/** Couleur rouge */
|
||||||
public static final String RED = "\u001b[31m";
|
public static final String RED = "\u001b[31m";
|
||||||
|
/** Couleur bleue */
|
||||||
public static final String BLUE = "\u001b[34m";
|
public static final String BLUE = "\u001b[34m";
|
||||||
|
/** Couleur standard */
|
||||||
public static final String RST = "\u001b[0m";
|
public static final String RST = "\u001b[0m";
|
||||||
|
/** Fin de message */
|
||||||
public static final String END_MESSAGE = "fin";
|
public static final String END_MESSAGE = "fin";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Socket connecté au serveur
|
||||||
|
*/
|
||||||
|
protected Socket sock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flux de caractères UTF-8 en sortie
|
||||||
|
*/
|
||||||
|
protected PrintStream out;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flux de caractères UTF-8 en entrée
|
||||||
|
*/
|
||||||
|
protected BufferedReader in;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chaine de caractères "ip:port" du client
|
||||||
|
*/
|
||||||
|
protected String ipPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le client est-il connecté ?
|
||||||
|
*/
|
||||||
|
protected boolean connected;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
|
|
@ -32,6 +58,11 @@ public class ClientTCP {
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Programme principal [Déprécié]
|
||||||
|
* @param args Arguments
|
||||||
|
* @throws Exception Si la connexion échoue
|
||||||
|
*/
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
/*
|
/*
|
||||||
ClientTCP client = new ClientTCP("localhost", 2024);
|
ClientTCP client = new ClientTCP("localhost", 2024);
|
||||||
|
|
@ -55,35 +86,13 @@ public class ClientTCP {
|
||||||
client.close();
|
client.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Socket connecté au serveur
|
|
||||||
*/
|
|
||||||
protected Socket sock;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flux de caractères UTF-8 en sortie
|
|
||||||
*/
|
|
||||||
protected PrintStream out;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flux de caractères UTF-8 en entrée
|
|
||||||
*/
|
|
||||||
protected BufferedReader in;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chaine de caractères "ip:port" du client
|
|
||||||
*/
|
|
||||||
protected String ipPort;
|
|
||||||
|
|
||||||
protected boolean connected;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Le constructeur ouvre la connexion TCP au serveur <code>host:port</code>
|
* Le constructeur ouvre la connexion TCP au serveur <code>host:port</code>
|
||||||
* et récupère les flux de caractères en entrée {@link #in} et sortie {@link #out}
|
* et récupère les flux de caractères en entrée {@link #in} et sortie {@link #out}
|
||||||
*import static rtgre.chat.ChatApplication.LOGGER;
|
*import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
* @param host IP ou nom de domaine du serveur
|
* @param host IP ou nom de domaine du serveur
|
||||||
* @param port port d'écoute du serveur
|
* @param port port d'écoute du serveur
|
||||||
* @throws IOException
|
* @throws IOException si la connexion échoue ou si les flux ne sont pas récupérables
|
||||||
*/
|
*/
|
||||||
public ClientTCP(String host, int port) throws IOException {
|
public ClientTCP(String host, int port) throws IOException {
|
||||||
System.out.printf("Connexion à [%s:%d]%n", host, port);
|
System.out.printf("Connexion à [%s:%d]%n", host, port);
|
||||||
|
|
@ -116,10 +125,18 @@ public class ClientTCP {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de connected
|
||||||
|
* @return L'état de connected
|
||||||
|
*/
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return connected;
|
return connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter de connected
|
||||||
|
* @param connected L'utilisateur est-il connecté ?
|
||||||
|
*/
|
||||||
public void setConnected(boolean connected) {
|
public void setConnected(boolean connected) {
|
||||||
this.connected = connected;
|
this.connected = connected;
|
||||||
}
|
}
|
||||||
|
|
@ -153,6 +170,9 @@ public class ClientTCP {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boucle d'envoi de messages
|
||||||
|
*/
|
||||||
public void sendLoop() {
|
public void sendLoop() {
|
||||||
System.out.println(BLUE + "Boucle d'envoi de messages..." + RST);
|
System.out.println(BLUE + "Boucle d'envoi de messages..." + RST);
|
||||||
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
|
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
|
@ -176,6 +196,9 @@ public class ClientTCP {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boucle de réception de messages
|
||||||
|
*/
|
||||||
public void receiveLoop() {
|
public void receiveLoop() {
|
||||||
System.out.println(RED + "Boucle de réception de messages..." + RST);
|
System.out.println(RED + "Boucle de réception de messages..." + RST);
|
||||||
connected = true;
|
connected = true;
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,25 @@ import java.util.Objects;
|
||||||
|
|
||||||
import static rtgre.chat.ChatApplication.LOGGER;
|
import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant un contact avec son `login`, son `avatar` et son état (connecté ou non)
|
||||||
|
*/
|
||||||
public class Contact {
|
public class Contact {
|
||||||
|
/** Le login du contact */
|
||||||
protected String login;
|
protected String login;
|
||||||
|
/** L'avatar du contact */
|
||||||
protected java.awt.Image avatar;
|
protected java.awt.Image avatar;
|
||||||
|
/** L'utilisateur est connecté ? */
|
||||||
protected boolean connected;
|
protected boolean connected;
|
||||||
|
/** Le salon courant */
|
||||||
protected String currentRoom;
|
protected String currentRoom;
|
||||||
|
/** Le compteur de messages non-lus */
|
||||||
protected UnreadCount unreadCount = new UnreadCount();
|
protected UnreadCount unreadCount = new UnreadCount();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crée un objet Contact
|
* Crée un objet Contact
|
||||||
* @param: String login
|
* @param login Login du contact
|
||||||
* @param: java.awt.Image avatar
|
* @param avatar Avatar du contact au format java.awt.Image
|
||||||
*/
|
*/
|
||||||
public Contact(String login, java.awt.Image avatar) {
|
public Contact(String login, java.awt.Image avatar) {
|
||||||
this.login = login;
|
this.login = login;
|
||||||
|
|
@ -36,9 +44,9 @@ public class Contact {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crée un objet Contact
|
* Crée un objet Contact
|
||||||
* @param: String login
|
* @param login Login du contact
|
||||||
* @param: boolean connected
|
* @param connected Utilisateur connecté ?
|
||||||
* @param: java.awt.Image avatar
|
* @param avatar au format java.awt.Image
|
||||||
*/
|
*/
|
||||||
public Contact(String login, boolean connected, java.awt.Image avatar) {
|
public Contact(String login, boolean connected, java.awt.Image avatar) {
|
||||||
this.login = login;
|
this.login = login;
|
||||||
|
|
@ -47,15 +55,19 @@ public class Contact {
|
||||||
this.currentRoom = null;
|
this.currentRoom = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de `currentRoom`
|
||||||
|
* @return Le salon actuel
|
||||||
|
*/
|
||||||
public String getCurrentRoom() {
|
public String getCurrentRoom() {
|
||||||
return currentRoom;
|
return currentRoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crée un objet Contact
|
* Crée un objet Contact
|
||||||
* @param: String login
|
* @param login Login du contact
|
||||||
* @param: boolean connected
|
* @param connected Utilisateur connecté ?
|
||||||
* @param: File banques_avatars
|
* @param banques_avatars Image contenant les avatars par défaut relatifs aux logins
|
||||||
*/
|
*/
|
||||||
public Contact(String login, boolean connected, File banques_avatars) {
|
public Contact(String login, boolean connected, File banques_avatars) {
|
||||||
this.login = login;
|
this.login = login;
|
||||||
|
|
@ -70,28 +82,52 @@ public class Contact {
|
||||||
this.currentRoom = null;
|
this.currentRoom = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de `login`
|
||||||
|
* @return Le login du contact
|
||||||
|
*/
|
||||||
public String getLogin() {
|
public String getLogin() {
|
||||||
return this.login;
|
return this.login;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de `avatar`
|
||||||
|
* @return L'avatar du contact au format java.awt.Image
|
||||||
|
*/
|
||||||
public java.awt.Image getAvatar() {
|
public java.awt.Image getAvatar() {
|
||||||
return this.avatar;
|
return this.avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Représentation textuelle de l'objet Contact
|
||||||
|
* @return Le contact au format `@login`
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "@" + this.login;
|
return "@" + this.login;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du booléen `connected`
|
||||||
|
* @return Le statut de connexion du contact
|
||||||
|
*/
|
||||||
public boolean isConnected() {
|
public boolean isConnected() {
|
||||||
return this.connected;
|
return this.connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter du booléen `connected`
|
||||||
|
* @param connected Le statut de connexion du contact
|
||||||
|
*/
|
||||||
public void setConnected(boolean connected) {
|
public void setConnected(boolean connected) {
|
||||||
this.connected = connected;
|
this.connected = connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Egalité de deux contacts, s'ils ont le même login
|
||||||
|
* @param o Le salon auquel est comparé
|
||||||
|
* @return true si sont égaux, false sinon
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
@ -105,10 +141,18 @@ public class Contact {
|
||||||
return Objects.hashCode(login);
|
return Objects.hashCode(login);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du compteur de messages non-lus
|
||||||
|
* @return L'object `UnreadCount` du contact
|
||||||
|
*/
|
||||||
public UnreadCount getUnreadCount() {
|
public UnreadCount getUnreadCount() {
|
||||||
return unreadCount;
|
return unreadCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sérialise le contact courant en objet JSON
|
||||||
|
* @return L'objet JSONObject sérialisé
|
||||||
|
*/
|
||||||
public JSONObject toJsonObject() {
|
public JSONObject toJsonObject() {
|
||||||
return new JSONObject()
|
return new JSONObject()
|
||||||
.put("login", this.login)
|
.put("login", this.login)
|
||||||
|
|
@ -116,20 +160,33 @@ public class Contact {
|
||||||
.put("avatar", Contact.imageToBase64((BufferedImage) avatar));
|
.put("avatar", Contact.imageToBase64((BufferedImage) avatar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sérialise le contact courant en chaîne de caractères au format JSON
|
||||||
|
* @return un String au format JSON
|
||||||
|
*/
|
||||||
public String toJson() {
|
public String toJson() {
|
||||||
return toJsonObject().toString();
|
return toJsonObject().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construit un objet Contact à partir d'un objet JSON et de la banque d'avatars
|
||||||
|
* @param jsonObject L'objet JSON source
|
||||||
|
* @param banque_avatars La banque d'avatars
|
||||||
|
* @return Un objet Contact
|
||||||
|
*/
|
||||||
public static Contact fromJSON(JSONObject jsonObject, File banque_avatars) {
|
public static Contact fromJSON(JSONObject jsonObject, File banque_avatars) {
|
||||||
return new Contact(jsonObject.getString("login"), jsonObject.getBoolean("connected"), banque_avatars);
|
return new Contact(jsonObject.getString("login"), jsonObject.getBoolean("connected"), banque_avatars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie une sous-image en fonction d'une banque d'image et d'un login.
|
||||||
|
* @param fichier La banque d'avatars
|
||||||
|
* @param login Le login dont on cherche l'avatar
|
||||||
|
* @return Un objet BufferedImage contenant l'image recherchée
|
||||||
|
* @throws IOException si le fichier est introucable
|
||||||
|
*/
|
||||||
public static BufferedImage avatarFromLogin(File fichier, String login) throws IOException {
|
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.
|
|
||||||
* @param: File fichier
|
|
||||||
* @param: String login
|
|
||||||
*/
|
|
||||||
BufferedImage img = ImageIO.read(fichier);
|
BufferedImage img = ImageIO.read(fichier);
|
||||||
int width = img.getWidth() / 9;
|
int width = img.getWidth() / 9;
|
||||||
int height = img.getHeight();
|
int height = img.getHeight();
|
||||||
|
|
@ -137,22 +194,39 @@ public class Contact {
|
||||||
return img.getSubimage(n*width, 0, width, height);
|
return img.getSubimage(n*width, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAvatarFromFile(File f) {
|
/**
|
||||||
|
* Initialise l'avatar du contact courant en fonction de son login actuel et d'un fichier de banque d'avatars
|
||||||
|
* @param file La banque d'avatars
|
||||||
|
*/
|
||||||
|
public void setAvatarFromFile(File file) {
|
||||||
try {
|
try {
|
||||||
this.avatar = avatarFromLogin(f, this.login);
|
this.avatar = avatarFromLogin(file, this.login);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("Erreur : " + e.getMessage());
|
System.out.println("Erreur : " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter de `avatar`
|
||||||
|
* @param avatar L'avatar au format java.awt.Image
|
||||||
|
*/
|
||||||
public void setAvatar(java.awt.Image avatar) {
|
public void setAvatar(java.awt.Image avatar) {
|
||||||
this.avatar = avatar;
|
this.avatar = avatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter de currentRoom
|
||||||
|
* @param currentRoom Le salon courant
|
||||||
|
*/
|
||||||
public void setCurrentRoom(String currentRoom) {
|
public void setCurrentRoom(String currentRoom) {
|
||||||
this.currentRoom = currentRoom;
|
this.currentRoom = currentRoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforme une image au format java.awt.Image ou BufferedImage en une image encodée en base64.
|
||||||
|
* @param img L'image en java.awt.Image ou en BufferedImage
|
||||||
|
* @return L'image encodée en base64 si l'image est chargée correctement, un String vide sinon
|
||||||
|
*/
|
||||||
public static String imageToBase64(BufferedImage img) {
|
public static String imageToBase64(BufferedImage img) {
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
|
|
@ -165,6 +239,11 @@ public class Contact {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforme une image encodée en base64 en une image au format java.awt.Image.
|
||||||
|
* @param avatar64 L'image encodée en base64
|
||||||
|
* @return L'image en java.awt.Image
|
||||||
|
*/
|
||||||
public static java.awt.Image base64ToImage(String avatar64) {
|
public static java.awt.Image base64ToImage(String avatar64) {
|
||||||
byte[] bytes64 = Base64.getDecoder().decode(avatar64);
|
byte[] bytes64 = Base64.getDecoder().decode(avatar64);
|
||||||
try {
|
try {
|
||||||
|
|
@ -176,6 +255,11 @@ public class Contact {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforme une image encodée en base64 en une image au format BufferedImage.
|
||||||
|
* @param avatar64 L'image encodée en base64
|
||||||
|
* @return L'image en BufferedImage
|
||||||
|
*/
|
||||||
public static BufferedImage base64ToBufferedImage(String avatar64) {
|
public static BufferedImage base64ToBufferedImage(String avatar64) {
|
||||||
byte[] bytes64 = Base64.getDecoder().decode(avatar64);
|
byte[] bytes64 = Base64.getDecoder().decode(avatar64);
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -8,10 +8,18 @@ import org.sqlite.JDBC;
|
||||||
|
|
||||||
import static rtgre.chat.ChatApplication.LOGGER;
|
import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant la connexion à la base de données des posts.
|
||||||
|
*/
|
||||||
public class DatabaseApi {
|
public class DatabaseApi {
|
||||||
|
/** Connexion à la base de données */
|
||||||
private Connection con;
|
private Connection con;
|
||||||
|
/** Curseur "statement" à exécuter */
|
||||||
private Statement stmt;
|
private Statement stmt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur par défaut : connecte la base de donnée et et créer un statement
|
||||||
|
*/
|
||||||
public DatabaseApi() {
|
public DatabaseApi() {
|
||||||
try {
|
try {
|
||||||
this.con = DriverManager.getConnection("jdbc:sqlite:target/dbase.db");
|
this.con = DriverManager.getConnection("jdbc:sqlite:target/dbase.db");
|
||||||
|
|
@ -24,6 +32,10 @@ public class DatabaseApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crée la base de données si elle n'existe pas déjà
|
||||||
|
* @param con La connexion à la base de données
|
||||||
|
*/
|
||||||
private void initDB(Connection con) {
|
private void initDB(Connection con) {
|
||||||
try {
|
try {
|
||||||
String sql = "CREATE TABLE IF NOT EXISTS `posts` ("
|
String sql = "CREATE TABLE IF NOT EXISTS `posts` ("
|
||||||
|
|
@ -42,6 +54,11 @@ public class DatabaseApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère un post selon son UUID
|
||||||
|
* @param uuid l'UUID du post
|
||||||
|
* @return Une liste de résultats contenant le Post
|
||||||
|
*/
|
||||||
public ResultSet getPostById(UUID uuid) {
|
public ResultSet getPostById(UUID uuid) {
|
||||||
String query = "SELECT * FROM posts WHERE id = " + uuid.toString();
|
String query = "SELECT * FROM posts WHERE id = " + uuid.toString();
|
||||||
try {
|
try {
|
||||||
|
|
@ -52,6 +69,11 @@ public class DatabaseApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère tous les posts dont le timestamp est supérieur à celui donné
|
||||||
|
* @param timestamp Le timestamp de comparaison
|
||||||
|
* @return Une liste de résultats contenant les posts, triés dans l'ordre chronologique
|
||||||
|
*/
|
||||||
public ResultSet getPostsSince(long timestamp) {
|
public ResultSet getPostsSince(long timestamp) {
|
||||||
String query = "SELECT * FROM posts WHERE timestamp >= " + timestamp + "ORDER BY timestamp DESC";
|
String query = "SELECT * FROM posts WHERE timestamp >= " + timestamp + "ORDER BY timestamp DESC";
|
||||||
try {
|
try {
|
||||||
|
|
@ -62,6 +84,10 @@ public class DatabaseApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère tous les posts de la base de données
|
||||||
|
* @return Une liste de résultats contenant tous les posts en base
|
||||||
|
*/
|
||||||
public ResultSet getPosts() {
|
public ResultSet getPosts() {
|
||||||
String query = "SELECT * FROM posts";
|
String query = "SELECT * FROM posts";
|
||||||
try {
|
try {
|
||||||
|
|
@ -72,6 +98,11 @@ public class DatabaseApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajoute un post dans la base
|
||||||
|
* @param post Le poste à ajouter
|
||||||
|
* @return `true` si le post a bien été ajouté, `false` si une erreur est survenue
|
||||||
|
*/
|
||||||
public boolean addPost(Post post) {
|
public boolean addPost(Post post) {
|
||||||
String query = "INSERT INTO posts VALUES (?, ?, ?, ?, ?)";
|
String query = "INSERT INTO posts VALUES (?, ?, ?, ?, ?)";
|
||||||
try {
|
try {
|
||||||
|
|
@ -90,6 +121,11 @@ public class DatabaseApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enlève un post de la base de données
|
||||||
|
* @param post Le post à retirer
|
||||||
|
* @return `true` si le post a bien été retiré, `false` si une erreur est survenue
|
||||||
|
*/
|
||||||
public boolean removePost(Post post) {
|
public boolean removePost(Post post) {
|
||||||
String query = "DELETE FROM posts WHERE id=?";
|
String query = "DELETE FROM posts WHERE id=?";
|
||||||
try {
|
try {
|
||||||
|
|
@ -105,6 +141,9 @@ public class DatabaseApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ferme la connexion à la base de données
|
||||||
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
try {
|
try {
|
||||||
con.close();
|
con.close();
|
||||||
|
|
|
||||||
|
|
@ -3,47 +3,95 @@ package rtgre.modeles;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant un évènement permettant un échange client/serveur pour une application de chat.
|
||||||
|
*/
|
||||||
public class Event {
|
public class Event {
|
||||||
|
/** Type de l'évènement client -> serveur : authentification */
|
||||||
public static final String AUTH = "AUTH";
|
public static final String AUTH = "AUTH";
|
||||||
|
/** Type de l'évènement client -> serveur : déconnexion */
|
||||||
public static final String QUIT = "QUIT";
|
public static final String QUIT = "QUIT";
|
||||||
|
/** Type de l'évènement client -> serveur : envoi d'un message */
|
||||||
public static final String MESG = "MESG";
|
public static final String MESG = "MESG";
|
||||||
|
/** Type de l'évènement client -> serveur : rejoindre un salon */
|
||||||
public static final String JOIN = "JOIN";
|
public static final String JOIN = "JOIN";
|
||||||
|
/** Type de l'évènement serveur -> client : envoi d'un post */
|
||||||
public static final String POST = "POST";
|
public static final String POST = "POST";
|
||||||
|
/** Type de l'évènement serveur -> client : informations sur un contact */
|
||||||
public static final String CONT = "CONT";
|
public static final String CONT = "CONT";
|
||||||
|
/** Type de l'évènement client -> serveur : demander la liste des contacts */
|
||||||
public static final String LIST_CONTACTS = "LSTC";
|
public static final String LIST_CONTACTS = "LSTC";
|
||||||
|
/** Type de l'évènement client -> serveur : demander la liste des posts */
|
||||||
public static final String LIST_POSTS = "LSTP";
|
public static final String LIST_POSTS = "LSTP";
|
||||||
|
/** Type de l'évènement système interne au client */
|
||||||
public static final String SYSTEM = "SYST";
|
public static final String SYSTEM = "SYST";
|
||||||
|
/** Type de l'évènement client -> serveur : demander la liste des salons */
|
||||||
public static final String LIST_ROOMS = "LSTR";
|
public static final String LIST_ROOMS = "LSTR";
|
||||||
|
/** Type de l'évènement serveur -> client : informations sur un salon de discussion */
|
||||||
public static final String ROOM = "ROOM";
|
public static final String ROOM = "ROOM";
|
||||||
|
/** Le type d'évènement de l'Event courant */
|
||||||
private final String type;
|
private final String type;
|
||||||
|
/** Le contenu de l'Event courant */
|
||||||
private final JSONObject content;
|
private final JSONObject content;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du type
|
||||||
|
* @return Le type de l'évènement
|
||||||
|
*/
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du contenu
|
||||||
|
* @return Le contenu de l'évènement
|
||||||
|
*/
|
||||||
public JSONObject getContent() {
|
public JSONObject getContent() {
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur par défaut à partir d'un type et d'un objet JSON servant de contenu
|
||||||
|
* @param type Le type de l'évènement
|
||||||
|
* @param content Le contenu de l'évènement
|
||||||
|
*/
|
||||||
public Event(String type, JSONObject content) {
|
public Event(String type, JSONObject content) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Représentation textuelle de l'objet
|
||||||
|
* @return Chaine de caractères représentant l'évènement
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Event{type=" + type + ", content=" + content.toString() + "}";
|
return "Event{type=" + type + ", content=" + content.toString() + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie l'objet JSON représentant l'évènement
|
||||||
|
* @return L'objet JSON représentant l'évènement
|
||||||
|
*/
|
||||||
public JSONObject toJsonObject() {
|
public JSONObject toJsonObject() {
|
||||||
return new JSONObject().put("type", type).put("content", content);
|
return new JSONObject().put("type", type).put("content", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sérialisation de la représentation JSON d'un évènement
|
||||||
|
* @return La chaine de caractères représentant l'évènement
|
||||||
|
*/
|
||||||
public String toJson() {
|
public String toJson() {
|
||||||
return toJsonObject().toString();
|
return toJsonObject().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Méthode de classe instanciant et renvoyant un évènement à partir d'une chaine de caractères représentant un évènement JSON
|
||||||
|
* @param json La représentation JSON d'un évènement
|
||||||
|
* @return L'évènement associé
|
||||||
|
* @throws JSONException s'il y a une erreur dans la sérialisation
|
||||||
|
*/
|
||||||
public static Event fromJson(String json) throws JSONException {
|
public static Event fromJson(String json) throws JSONException {
|
||||||
JSONObject jsonObject = new JSONObject(json);
|
JSONObject jsonObject = new JSONObject(json);
|
||||||
String type = jsonObject.getString("type");
|
String type = jsonObject.getString("type");
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,45 @@
|
||||||
package rtgre.modeles;
|
package rtgre.modeles;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant un message adressé à un destinataire
|
||||||
|
*/
|
||||||
public class Message {
|
public class Message {
|
||||||
/**
|
/** Login du destinataire du message */
|
||||||
* Un message décrit sous la forme :
|
|
||||||
* @serialField : String to: Le destinataire
|
|
||||||
* @serialField : String body: le corps du message
|
|
||||||
*/
|
|
||||||
protected String to;
|
protected String to;
|
||||||
|
/** Contenu textuel du message */
|
||||||
protected String body;
|
protected String body;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur par défaut
|
||||||
|
* @param to Le destinataire du message
|
||||||
|
* @param body Le contenu du message
|
||||||
|
*/
|
||||||
public Message(String to, String body) {
|
public Message(String to, String body) {
|
||||||
|
|
||||||
this.to = to;
|
this.to = to;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de `to`
|
||||||
|
* @return Le destinataire du message
|
||||||
|
*/
|
||||||
public String getTo() {
|
public String getTo() {
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de `body`
|
||||||
|
* @return Le message sous la forme d'une chaine de caractères
|
||||||
|
*/
|
||||||
public String getBody() {
|
public String getBody() {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Représentation textuelle d'un message
|
||||||
|
* @return La chaine de caractère représentant un message
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Message{" +
|
return "Message{" +
|
||||||
|
|
@ -33,27 +48,30 @@ public class Message {
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie l'objet JSON représentant un message
|
||||||
|
* @return L'objet JSON
|
||||||
|
*/
|
||||||
public JSONObject toJsonObject() {
|
public JSONObject toJsonObject() {
|
||||||
/**
|
|
||||||
* Transforme le message courant en objet JSON
|
|
||||||
*/
|
|
||||||
return new JSONObject()
|
return new JSONObject()
|
||||||
.put("to", this.to)
|
.put("to", this.to)
|
||||||
.put("body", this.body);
|
.put("body", this.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sérialise dans une chaine de caractères la représentation JSON d'un message
|
||||||
|
* @return La représentation textuelle associée à la représentation JSON d'un message
|
||||||
|
*/
|
||||||
public String toJson() {
|
public String toJson() {
|
||||||
/**
|
|
||||||
* Transforme l'objet courant en String JSON
|
|
||||||
*/
|
|
||||||
return toJsonObject().toString();
|
return toJsonObject().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message sur la base d'une représentation JSON
|
||||||
|
* @param json La représentation JSON
|
||||||
|
* @return Un message
|
||||||
|
*/
|
||||||
public static Message fromJson(JSONObject json) {
|
public static Message fromJson(JSONObject json) {
|
||||||
/**
|
|
||||||
* Crée un objet message à partir d'un objet JSON
|
|
||||||
* @param: JSONObject json: l'objet JSON à transformer
|
|
||||||
*/
|
|
||||||
return new Message(json.getString("to"), json.getString("body"));
|
return new Message(json.getString("to"), json.getString("body"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,28 +4,41 @@ import org.json.JSONObject;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant un post échangé entre un émetteur et un destinataire privé ou public
|
||||||
|
*/
|
||||||
public class Post extends Message {
|
public class Post extends Message {
|
||||||
|
|
||||||
|
/** Identifiant unique du post */
|
||||||
protected UUID id;
|
protected UUID id;
|
||||||
|
/** Horodatage du post exprimé en nombre de millisecondes depuis le 01/01/1970 */
|
||||||
protected long timestamp;
|
protected long timestamp;
|
||||||
|
/** Login du contact qui a envoyé ce post */
|
||||||
protected String from;
|
protected String from;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur par défaut
|
||||||
|
* @param id L'identifiant du post
|
||||||
|
* @param timestamp Le timestamp du post
|
||||||
|
* @param from L'émetteur du post
|
||||||
|
* @param to Le destinataire du post
|
||||||
|
* @param body Le contenu du post
|
||||||
|
*/
|
||||||
public Post(UUID id, long timestamp, String from, String to, String body) {
|
public Post(UUID id, long timestamp, String from, String to, String body) {
|
||||||
/**
|
|
||||||
* Crée un objet Post
|
|
||||||
* @param: UUID id
|
|
||||||
* @param: long timestamp
|
|
||||||
* @param: String from
|
|
||||||
* @param: String to,
|
|
||||||
* @param: String body
|
|
||||||
*/
|
|
||||||
super(to, body);
|
super(to, body);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.from = from;
|
this.from = from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur d'un post sur la base de son émetteur, son destinataire et son contenu. L'identifiant est choisi de manière unique aléatoirement ; le timestamp correspond à la date courante
|
||||||
|
* @param from L'émetteur du post
|
||||||
|
* @param to Le destinataire du post
|
||||||
|
* @param body Le contenu du post
|
||||||
|
*/
|
||||||
public Post(String from, String to, String body) {
|
public Post(String from, String to, String body) {
|
||||||
super(to, body);
|
super(to, body);
|
||||||
this.from = from;
|
this.from = from;
|
||||||
|
|
@ -35,6 +48,11 @@ public class Post extends Message {
|
||||||
this.id = UUID.randomUUID();
|
this.id = UUID.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur à partir d'un Message
|
||||||
|
* @param from Login de l'émetteur
|
||||||
|
* @param message Message (incluant le destinataire et le contenu)
|
||||||
|
*/
|
||||||
public Post(String from, Message message) {
|
public Post(String from, Message message) {
|
||||||
super(message.to, message.body);
|
super(message.to, message.body);
|
||||||
this.from = from;
|
this.from = from;
|
||||||
|
|
@ -44,6 +62,11 @@ public class Post extends Message {
|
||||||
this.id = UUID.randomUUID();
|
this.id = UUID.randomUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Egalité de deux posts, s'ils ont le même identifiant unique
|
||||||
|
* @param o Le post auquel est comparé
|
||||||
|
* @return true si sont égaux, false sinon
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
@ -57,18 +80,34 @@ public class Post extends Message {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de l'identifiant
|
||||||
|
* @return L'identifiant
|
||||||
|
*/
|
||||||
public UUID getId() {
|
public UUID getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter du timestamp
|
||||||
|
* @return Le timestamp
|
||||||
|
*/
|
||||||
public long getTimestamp() {
|
public long getTimestamp() {
|
||||||
return timestamp;
|
return timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de l'émeteur
|
||||||
|
* @return L'émetteur
|
||||||
|
*/
|
||||||
public String getFrom() {
|
public String getFrom() {
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Représentation textuelle du post
|
||||||
|
* @return La représentation textuelle du post
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Post{" +
|
return "Post{" +
|
||||||
|
|
@ -80,6 +119,10 @@ public class Post extends Message {
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Objet JSON représentant un post
|
||||||
|
* @return La représentation JSON d'un post
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public JSONObject toJsonObject() {
|
public JSONObject toJsonObject() {
|
||||||
return new JSONObject()
|
return new JSONObject()
|
||||||
|
|
@ -90,11 +133,20 @@ public class Post extends Message {
|
||||||
.put("body", this.body);
|
.put("body", this.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sérialise dans une chaine de caractères la représentation JSON d'un objet.
|
||||||
|
* @return La représentation textuelle associée à la représentation JSON d'un post
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toJson() {
|
public String toJson() {
|
||||||
return toJsonObject().toString();
|
return toJsonObject().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Création d'un post à partir d'un objet JSON représentant un post
|
||||||
|
* @param jsonObject L'objet JSON représentant un post
|
||||||
|
* @return Le post créé
|
||||||
|
*/
|
||||||
public static Post fromJson(JSONObject jsonObject) {
|
public static Post fromJson(JSONObject jsonObject) {
|
||||||
return new Post(
|
return new Post(
|
||||||
UUID.fromString(jsonObject.getString("id")),
|
UUID.fromString(jsonObject.getString("id")),
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,16 @@ import java.util.Vector;
|
||||||
|
|
||||||
import static rtgre.chat.ChatApplication.LOGGER;
|
import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant une liste de posts
|
||||||
|
*/
|
||||||
public class PostVector extends Vector<Post> {
|
public class PostVector extends Vector<Post> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrait un post en fonction de son identifiant
|
||||||
|
* @param uuid L'identifiant du post recherché
|
||||||
|
* @return Le post correspondant
|
||||||
|
*/
|
||||||
public Post getPostById(UUID uuid) {
|
public Post getPostById(UUID uuid) {
|
||||||
for (Post post : this) {
|
for (Post post : this) {
|
||||||
if (post.id == uuid) {
|
if (post.id == uuid) {
|
||||||
|
|
@ -18,6 +26,11 @@ public class PostVector extends Vector<Post> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie la liste des posts, qui ont été créé à partir d'un timestamp donné
|
||||||
|
* @param timestamp Le timestamp à partir duquel extraire les posts
|
||||||
|
* @return La liste des posts extraits
|
||||||
|
*/
|
||||||
public Vector<Post> getPostsSince(long timestamp) {
|
public Vector<Post> getPostsSince(long timestamp) {
|
||||||
Vector<Post> posts = new Vector<>();
|
Vector<Post> posts = new Vector<>();
|
||||||
for (Post post : this) {
|
for (Post post : this) {
|
||||||
|
|
@ -28,6 +41,9 @@ public class PostVector extends Vector<Post> {
|
||||||
return posts;
|
return posts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charge la liste des posts depuis la base de données
|
||||||
|
*/
|
||||||
public void loadPosts() {
|
public void loadPosts() {
|
||||||
try {
|
try {
|
||||||
DatabaseApi database = new DatabaseApi();
|
DatabaseApi database = new DatabaseApi();
|
||||||
|
|
|
||||||
|
|
@ -5,38 +5,73 @@ import org.json.JSONObject;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant un salon avec son nom et sa liste d'utilisateurs autorisés.
|
||||||
|
*/
|
||||||
public class Room {
|
public class Room {
|
||||||
|
/** Le nom du salon */
|
||||||
protected String roomName;
|
protected String roomName;
|
||||||
|
/** La liste des utilisateurs autorisés à rejoindre le salon. Si `null`, tout le monde peut poster */
|
||||||
protected HashSet<String> loginSet;
|
protected HashSet<String> loginSet;
|
||||||
|
/** Le compteur de messages non-lus */
|
||||||
protected UnreadCount unreadCount = new UnreadCount();
|
protected UnreadCount unreadCount = new UnreadCount();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le getter associé à roomName
|
||||||
|
* @return Le nom du salon
|
||||||
|
*/
|
||||||
public String getRoomName() {
|
public String getRoomName() {
|
||||||
return roomName;
|
return roomName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le getter associé au loginSet
|
||||||
|
* @return La liste des utilisateurs autorisés à rejoindre le salon
|
||||||
|
*/
|
||||||
public HashSet<String> getLoginSet() {
|
public HashSet<String> getLoginSet() {
|
||||||
return loginSet;
|
return loginSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur par défaut
|
||||||
|
* @param roomName Le nom du salon
|
||||||
|
*/
|
||||||
public Room(String roomName) {
|
public Room(String roomName) {
|
||||||
this.roomName = roomName;
|
this.roomName = roomName;
|
||||||
this.loginSet = null;
|
this.loginSet = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abréviation du nom du salon avec la 1re lettre de son nom
|
||||||
|
* @return La première lettre du nom du salon (# non compris)
|
||||||
|
*/
|
||||||
public String abbreviation() {
|
public String abbreviation() {
|
||||||
return this.roomName.split("#")[1].substring(0, 1);
|
return this.roomName.split("#")[1].substring(0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Représentation textuelle d'un salon
|
||||||
|
* @return Le nom du salon
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.roomName;
|
return this.roomName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter de LoginSet
|
||||||
|
* @param loginSet La liste des utilisateurs autorisés à se connecter au salon
|
||||||
|
*/
|
||||||
public void setLoginSet (HashSet<String> loginSet) {
|
public void setLoginSet (HashSet<String> loginSet) {
|
||||||
this.loginSet = loginSet;
|
this.loginSet = loginSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Egalité de deux salons, s'ils ont le même nom
|
||||||
|
* @param o Le salon auquel est comparé
|
||||||
|
* @return true si sont égaux, false sinon
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
@ -45,6 +80,10 @@ public class Room {
|
||||||
return Objects.equals(roomName, room.roomName);
|
return Objects.equals(roomName, room.roomName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajoute un login au contact du salon (en créant le loginSet au besoin)
|
||||||
|
* @param login Le login du contact à ajouter au salon
|
||||||
|
*/
|
||||||
public void add(String login) {
|
public void add(String login) {
|
||||||
if (loginSet == null) {
|
if (loginSet == null) {
|
||||||
loginSet = new HashSet<>();
|
loginSet = new HashSet<>();
|
||||||
|
|
@ -52,16 +91,28 @@ public class Room {
|
||||||
loginSet.add(login);
|
loginSet.add(login);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Représentation JSON d'un salon, incluant son nom et la liste des utilisateurs autorisés à y poster
|
||||||
|
* @return La représentation JSON
|
||||||
|
*/
|
||||||
public JSONObject toJsonObject() {
|
public JSONObject toJsonObject() {
|
||||||
return new JSONObject()
|
return new JSONObject()
|
||||||
.put("room", this.roomName)
|
.put("room", this.roomName)
|
||||||
.put("loginSet", this.loginSet);
|
.put("loginSet", this.loginSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chaine de caractères associée à la représentation JSON d'un contact
|
||||||
|
* @return La chaine de caractères correspondant à la représentation JSON
|
||||||
|
*/
|
||||||
public String toJson() {
|
public String toJson() {
|
||||||
return this.toJsonObject().toString();
|
return this.toJsonObject().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de l'unreadCount
|
||||||
|
* @return Le compteur de messages non-lus
|
||||||
|
*/
|
||||||
public UnreadCount getUnreadCount() {
|
public UnreadCount getUnreadCount() {
|
||||||
return this.unreadCount;
|
return this.unreadCount;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,21 @@ package rtgre.modeles;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modélise un annuaire des salons sous la forme d’un tableau associatif clé=“#nom de salon” ⇒ valeur=“objet Room”.
|
||||||
|
*/
|
||||||
public class RoomMap extends TreeMap<String, Room> {
|
public class RoomMap extends TreeMap<String, Room> {
|
||||||
|
/**
|
||||||
|
* Ajoute un salon à l'annuaire des salons
|
||||||
|
* @param room Le salon à ajouter
|
||||||
|
*/
|
||||||
public void add(Room room) {
|
public void add(Room room) {
|
||||||
this.put(room.getRoomName(), room);
|
this.put(room.getRoomName(), room);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charge 4 salons dans l'annuaire des salons : "`#all`", "`#juniors`", "`#ducks`", "`#mice`"
|
||||||
|
*/
|
||||||
public void loadDefaultRooms() {
|
public void loadDefaultRooms() {
|
||||||
this.add(new Room("#all"));
|
this.add(new Room("#all"));
|
||||||
this.add(new Room("#juniors"));
|
this.add(new Room("#juniors"));
|
||||||
|
|
@ -15,6 +25,9 @@ public class RoomMap extends TreeMap<String, Room> {
|
||||||
this.add(new Room("#mice"));
|
this.add(new Room("#mice"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charge les listes des utilisateurs autorisés pour les 4 salons chargés au préalable
|
||||||
|
*/
|
||||||
public void setLoginSets() {
|
public void setLoginSets() {
|
||||||
|
|
||||||
HashSet<String> juniors = new HashSet<>();
|
HashSet<String> juniors = new HashSet<>();
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,33 @@
|
||||||
package rtgre.modeles;
|
package rtgre.modeles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classe modélisant le compteur de messages non-lus
|
||||||
|
*/
|
||||||
public class UnreadCount {
|
public class UnreadCount {
|
||||||
|
/** Le compteur */
|
||||||
private int unreadCount = 0;
|
private int unreadCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Incrémente le compteur de posts reçus, mais non lus unreadCount et renvoie sa valeur.
|
||||||
|
* @return Le compteur après incrémentation
|
||||||
|
*/
|
||||||
public int incrementUnreadCount() {
|
public int incrementUnreadCount() {
|
||||||
unreadCount += 1;
|
unreadCount += 1;
|
||||||
return unreadCount;
|
return unreadCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter de unreadCount
|
||||||
|
* @param unreadCount La valeur à donner à unreadCount
|
||||||
|
*/
|
||||||
public void setUnreadCount(int unreadCount) {
|
public void setUnreadCount(int unreadCount) {
|
||||||
this.unreadCount = unreadCount;
|
this.unreadCount = unreadCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de unreadCount
|
||||||
|
* @return Le compteur
|
||||||
|
*/
|
||||||
public int getUnreadCount() {
|
public int getUnreadCount() {
|
||||||
return unreadCount;
|
return unreadCount;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,11 +23,19 @@ import static rtgre.chat.ChatApplication.LOGGER;
|
||||||
*/
|
*/
|
||||||
public class ChatServer {
|
public class ChatServer {
|
||||||
|
|
||||||
|
/** Liste des clients connectés */
|
||||||
private Vector<ChatClientHandler> clientList;
|
private Vector<ChatClientHandler> clientList;
|
||||||
|
/** Liste des messages */
|
||||||
private PostVector postVector;
|
private PostVector postVector;
|
||||||
|
/** Annuaire des contacts */
|
||||||
private ContactMap contactMap;
|
private ContactMap contactMap;
|
||||||
|
/** Liste des salons */
|
||||||
private RoomMap roomMap;
|
private RoomMap roomMap;
|
||||||
|
/** Connexion à la base de données */
|
||||||
private DatabaseApi database;
|
private DatabaseApi database;
|
||||||
|
/** Socket passif en écoute */
|
||||||
|
private ServerSocket passiveSock;
|
||||||
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
|
|
@ -39,23 +47,28 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Le programme principal : instancie un serveur en écoute sur le port 2024 et le place en attente de clients.
|
||||||
|
* @param args Arguments du programme principal
|
||||||
|
* @throws IOException en cas de problème de connexion ou de base de données
|
||||||
|
*/
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
try {
|
try {
|
||||||
Class.forName("org.sqlite.JDBC");
|
Class.forName("org.sqlite.JDBC");
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
throw new RuntimeException(e);
|
throw new IOException("Cannot connect to database");
|
||||||
}
|
}
|
||||||
ChatServer server = new ChatServer(2024);
|
ChatServer server = new ChatServer(2024);
|
||||||
//daisyConnect();
|
//daisyConnect();
|
||||||
server.acceptClients();
|
server.acceptClients();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Socket passif en écoute
|
|
||||||
*/
|
|
||||||
private ServerSocket passiveSock;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructeur : initialisation du serveur, en écoute sur le port fourni
|
||||||
|
* @param port Le port de connexion
|
||||||
|
* @throws IOException si la connexion ne peut être établie
|
||||||
|
*/
|
||||||
public ChatServer(int port) throws IOException {
|
public ChatServer(int port) throws IOException {
|
||||||
passiveSock = new ServerSocket(port);
|
passiveSock = new ServerSocket(port);
|
||||||
LOGGER.info("Serveur en écoute " + passiveSock);
|
LOGGER.info("Serveur en écoute " + passiveSock);
|
||||||
|
|
@ -69,6 +82,26 @@ public class ChatServer {
|
||||||
postVector.loadPosts();
|
postVector.loadPosts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de `PostVector`
|
||||||
|
* @return La liste des posts
|
||||||
|
*/
|
||||||
|
public PostVector getPostVector() {
|
||||||
|
return postVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de `roomMap`
|
||||||
|
* @return La liste des salons
|
||||||
|
*/
|
||||||
|
public RoomMap getRoomMap() {
|
||||||
|
return roomMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ferme la connexion du serveur, en fermant la connexion auprès de tous ses clients, puis en fermant son socket en écoute passive.
|
||||||
|
* @throws IOException si la connexion
|
||||||
|
*/
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
for (ChatClientHandler client : clientList) {
|
for (ChatClientHandler client : clientList) {
|
||||||
client.close();
|
client.close();
|
||||||
|
|
@ -95,16 +128,28 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retire `client` de la liste des clients connectés `clientList`
|
||||||
|
* @param client client à retirer de la liste `clientList`
|
||||||
|
*/
|
||||||
public void removeClient(ChatClientHandler client) {
|
public void removeClient(ChatClientHandler client) {
|
||||||
clientList.remove(client);
|
clientList.remove(client);
|
||||||
LOGGER.fine("Client [%s] retiré de la liste (%d clients connectés)"
|
LOGGER.fine("Client [%s] retiré de la liste (%d clients connectés)"
|
||||||
.formatted(client.getIpPort(), clientList.size()));
|
.formatted(client.getIpPort(), clientList.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de `clientList`
|
||||||
|
* @return La liste des clients
|
||||||
|
*/
|
||||||
public Vector<ChatClientHandler> getClientList() {
|
public Vector<ChatClientHandler> getClientList() {
|
||||||
return clientList;
|
return clientList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de passiveSocket
|
||||||
|
* @return Le socket en écoute passive du serveur
|
||||||
|
*/
|
||||||
public ServerSocket getPassiveSocket() {
|
public ServerSocket getPassiveSocket() {
|
||||||
return passiveSock;
|
return passiveSock;
|
||||||
}
|
}
|
||||||
|
|
@ -125,6 +170,11 @@ public class ChatServer {
|
||||||
//client.echoLoop();
|
//client.echoLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renvoie le client de connexion (objet ChatServer.ChatClientHandler) associé à un contact
|
||||||
|
* @param contact Le contact recherché
|
||||||
|
* @return Le client de connexion associé ou `null` si le contact n'existe pas
|
||||||
|
*/
|
||||||
public ChatClientHandler findClient(Contact contact) {
|
public ChatClientHandler findClient(Contact contact) {
|
||||||
for (ChatClientHandler user: clientList) {
|
for (ChatClientHandler user: clientList) {
|
||||||
if (user.user.equals(contact)) {
|
if (user.user.equals(contact)) {
|
||||||
|
|
@ -134,6 +184,11 @@ public class ChatServer {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi d'un évènement event à un contact donné, sous réserve qu'il soit connecté. Si l'envoi échoue, ferme la connexion avec le contact.
|
||||||
|
* @param contact Le contact destinataire
|
||||||
|
* @param event L'évènement à envoyer
|
||||||
|
*/
|
||||||
public void sendEventToContact(Contact contact, Event event) {
|
public void sendEventToContact(Contact contact, Event event) {
|
||||||
ChatClientHandler user = findClient(contact);
|
ChatClientHandler user = findClient(contact);
|
||||||
if (!(user == null)) {
|
if (!(user == null)) {
|
||||||
|
|
@ -146,6 +201,10 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoi d'un évènement à tous les contacts connectés
|
||||||
|
* @param event L'évènement à envoyer
|
||||||
|
*/
|
||||||
public void sendEventToAllContacts(Event event) {
|
public void sendEventToAllContacts(Event event) {
|
||||||
for (Contact contact: contactMap.values()) {
|
for (Contact contact: contactMap.values()) {
|
||||||
if (contact.isConnected()) {
|
if (contact.isConnected()) {
|
||||||
|
|
@ -154,17 +213,28 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de contactMap
|
||||||
|
* @return La liste des contacts
|
||||||
|
*/
|
||||||
public ContactMap getContactMap() {
|
public ContactMap getContactMap() {
|
||||||
return contactMap;
|
return contactMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Temporaire : connecte pour test */
|
/**
|
||||||
|
* Temporaire : connecte daisy pour test
|
||||||
|
* @throws IOException si la connexion ne peut être établie
|
||||||
|
*/
|
||||||
public static void daisyConnect() throws IOException {
|
public static void daisyConnect() throws IOException {
|
||||||
ChatClient client = new ChatClient("localhost", 2024, null);
|
ChatClient client = new ChatClient("localhost", 2024, null);
|
||||||
client.sendAuthEvent(new Contact("daisy", null));
|
client.sendAuthEvent(new Contact("daisy", null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gestion du dialogue avec un client TCP
|
||||||
|
*/
|
||||||
private class ChatClientHandler {
|
private class ChatClientHandler {
|
||||||
|
/** Message de fin d'une connexion */
|
||||||
public static final String END_MESSAGE = "fin";
|
public static final String END_MESSAGE = "fin";
|
||||||
/**
|
/**
|
||||||
* Socket connecté au client
|
* Socket connecté au client
|
||||||
|
|
@ -182,7 +252,7 @@ public class ChatServer {
|
||||||
* Chaine de caractères "ip:port" du client
|
* Chaine de caractères "ip:port" du client
|
||||||
*/
|
*/
|
||||||
private String ipPort;
|
private String ipPort;
|
||||||
|
/** Contact associé au client courant */
|
||||||
private Contact user;
|
private Contact user;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -191,7 +261,7 @@ public class ChatServer {
|
||||||
* {@link #in} (flux de caractères UTF-8 en entrée).
|
* {@link #in} (flux de caractères UTF-8 en entrée).
|
||||||
*
|
*
|
||||||
* @param sock socket connecté au client
|
* @param sock socket connecté au client
|
||||||
* @throws IOException
|
* @throws IOException si la connexion ne peut être établie ou si les flux ne peuvent être récupérés
|
||||||
*/
|
*/
|
||||||
public ChatClientHandler(Socket sock) throws IOException {
|
public ChatClientHandler(Socket sock) throws IOException {
|
||||||
this.sock = sock;
|
this.sock = sock;
|
||||||
|
|
@ -225,6 +295,9 @@ public class ChatServer {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boucle de réception d'évènement : réceptionne les messages reçus et les délèguent à `handleEvent(java.lang.String)` pour les interpréter
|
||||||
|
*/
|
||||||
public void eventReceiveLoop() {
|
public void eventReceiveLoop() {
|
||||||
try {
|
try {
|
||||||
String message = null;
|
String message = null;
|
||||||
|
|
@ -249,6 +322,13 @@ public class ChatServer {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traitement d'un évènement. Ventile vers les méthodes traitant chaque type d'évènement.
|
||||||
|
* @param message objet évènement sous la forme d'une chaine JSON brute de réception
|
||||||
|
* @return `false` si l'évènement est de type Event.QUIT , `true` pour tous les autres types.
|
||||||
|
* @throws JSONException si l'objet JSON n'est pas conforme
|
||||||
|
* @throws IllegalStateException si l'authentification n'est pas effectuée
|
||||||
|
*/
|
||||||
private boolean handleEvent(String message) throws JSONException, IllegalStateException {
|
private boolean handleEvent(String message) throws JSONException, IllegalStateException {
|
||||||
Event event = Event.fromJson(message);
|
Event event = Event.fromJson(message);
|
||||||
if (event.getType().equals(Event.AUTH)) {
|
if (event.getType().equals(Event.AUTH)) {
|
||||||
|
|
@ -292,6 +372,10 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour un Post en fonction de son UUID
|
||||||
|
* @param content le contenu d'un évènement "POST"
|
||||||
|
*/
|
||||||
private void doPost(JSONObject content) {
|
private void doPost(JSONObject content) {
|
||||||
database = new DatabaseApi();
|
database = new DatabaseApi();
|
||||||
database.removePost(Post.fromJson(content));
|
database.removePost(Post.fromJson(content));
|
||||||
|
|
@ -303,6 +387,10 @@ public class ChatServer {
|
||||||
LOGGER.info("didpost");
|
LOGGER.info("didpost");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Met à jour un contact et envoie à tous les autres utilisateurs la mise à jour
|
||||||
|
* @param content Le contenu d'un évènement "CONT"
|
||||||
|
*/
|
||||||
private void doCont(JSONObject content) {
|
private void doCont(JSONObject content) {
|
||||||
if (user.isConnected()) {
|
if (user.isConnected()) {
|
||||||
sendEventToAllContacts(new Event("CONT", content));
|
sendEventToAllContacts(new Event("CONT", content));
|
||||||
|
|
@ -310,6 +398,10 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gère l'arrivée à un utilisateur dans un salon donné dans le contenu du message.
|
||||||
|
* @param content Le contenu d'un évènement "JOIN"
|
||||||
|
*/
|
||||||
private void doJoin(JSONObject content) {
|
private void doJoin(JSONObject content) {
|
||||||
if (content.getString("room").isEmpty()) {
|
if (content.getString("room").isEmpty()) {
|
||||||
user.setCurrentRoom(null);
|
user.setCurrentRoom(null);
|
||||||
|
|
@ -326,6 +418,10 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gère la demande d'envoi de la liste des salons : récupère tous les posts dont l'utilisateur est autorisé à accéder, puis les envoie un par un au client via des évènements "ROOM".
|
||||||
|
* @param content Le contenu d'un évènement "LSTR"
|
||||||
|
*/
|
||||||
private void doListRoom(JSONObject content) {
|
private void doListRoom(JSONObject content) {
|
||||||
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
||||||
for (Room room: roomMap.values()) {
|
for (Room room: roomMap.values()) {
|
||||||
|
|
@ -340,6 +436,12 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gère la demande d'envoi de la liste des posts : récupère tous les posts ayant trait au login ou au salon indiqué dans content et étant postérieur au timestamp indiqué dans content, puis les envoie un par un au client via des évènements "POST".
|
||||||
|
* @param content Le contenu d'un évènement "LSTP"
|
||||||
|
* @throws JSONException si le format JSON n'est pas respecté
|
||||||
|
* @throws IllegalStateException si le login ou le salon demandé n'existent pas
|
||||||
|
*/
|
||||||
private void doListPost(JSONObject content) throws JSONException, IllegalStateException {
|
private void doListPost(JSONObject content) throws JSONException, IllegalStateException {
|
||||||
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
||||||
if (!contactMap.containsKey(content.getString("select")) && !roomMap.containsKey(content.getString("select"))) {
|
if (!contactMap.containsKey(content.getString("select")) && !roomMap.containsKey(content.getString("select"))) {
|
||||||
|
|
@ -365,6 +467,12 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gère la réception d'un message, en créant le Post associé et en l'envoyant à son destinataire privé ou aux membres d'un salon de discussion public
|
||||||
|
* @param content Le contenu JSON représentant un message
|
||||||
|
* @throws JSONException si le format JSON n'est pas respecté
|
||||||
|
* @throws IllegalStateException si un évènement destiné à un contact ne peut être envoyé
|
||||||
|
*/
|
||||||
private void doMessage(JSONObject content) throws JSONException, IllegalStateException {
|
private void doMessage(JSONObject content) throws JSONException, IllegalStateException {
|
||||||
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
||||||
if (content.getString("to").equals(user.getLogin()) ||
|
if (content.getString("to").equals(user.getLogin()) ||
|
||||||
|
|
@ -408,6 +516,12 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gère la demande de la liste des contacts : les contacts sont envoyés un par un au client sous la forme d'évènement "CONT"
|
||||||
|
* @param content Le contenu de la demande de la liste des contacts
|
||||||
|
* @throws JSONException si le format JSON n'est pas respecté
|
||||||
|
* @throws IllegalStateException si un évènement destiné à un contact ne peut être envoyé
|
||||||
|
*/
|
||||||
private void doListContact(JSONObject content) throws JSONException, IllegalStateException {
|
private void doListContact(JSONObject content) throws JSONException, IllegalStateException {
|
||||||
for (Contact contact: contactMap.values()) {
|
for (Contact contact: contactMap.values()) {
|
||||||
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
if (contactMap.getContact(user.getLogin()).isConnected()) {
|
||||||
|
|
@ -416,7 +530,18 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doLogin(JSONObject content) {
|
/**
|
||||||
|
* Gère l'authentification d'un client en :
|
||||||
|
* * récupérant son login dans content.
|
||||||
|
* * en vérifiant qu'il fait partie des contacts autorisés dans l'annuaire des contacts.
|
||||||
|
* * en modifiant son état de connexion dans l'annuaire des contacts.
|
||||||
|
* * en informant les autres clients de la connexion.
|
||||||
|
* Si aucun login n'est fourni, si le client n'est pas autorisé à se connecter, ou si le client s'authentifie alors qu'il est déjà connecté, une exception IllegalStateException est levée.
|
||||||
|
* @param content Le contenu de la demande
|
||||||
|
* @throws JSONException si le format JSON n'est pas respecté
|
||||||
|
* @throws IllegalStateException si l'utilisateur n'est pas autorisé à se connecter ou s'il est déjà connecté
|
||||||
|
*/
|
||||||
|
private void doLogin(JSONObject content) throws JSONException, IllegalStateException {
|
||||||
String login = content.getString("login");
|
String login = content.getString("login");
|
||||||
if (login.isEmpty()) {
|
if (login.isEmpty()) {
|
||||||
LOGGER.warning("Aucun login fourni");
|
LOGGER.warning("Aucun login fourni");
|
||||||
|
|
@ -436,6 +561,11 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie une chaine de caractères
|
||||||
|
* @param message Chaine de caractères à transmettre
|
||||||
|
* @throws IOException lorsqu'une erreur sur le flux de sortie est détectée
|
||||||
|
*/
|
||||||
public void send(String message) throws IOException {
|
public void send(String message) throws IOException {
|
||||||
LOGGER.finest("send: %s".formatted(message));
|
LOGGER.finest("send: %s".formatted(message));
|
||||||
out.println(message);
|
out.println(message);
|
||||||
|
|
@ -444,10 +574,19 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Getter de ipPort
|
||||||
|
* @return L'IP et le port du client
|
||||||
|
*/
|
||||||
public String getIpPort() {
|
public String getIpPort() {
|
||||||
return ipPort;
|
return ipPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envoie un message à tous les autres clients que le client courant
|
||||||
|
* @param fromClient Le client courant
|
||||||
|
* @param message Le message à envoyer
|
||||||
|
*/
|
||||||
public void sendAllOtherClients(ChatClientHandler fromClient, String message) {
|
public void sendAllOtherClients(ChatClientHandler fromClient, String message) {
|
||||||
for (ChatClientHandler client : clientList) {
|
for (ChatClientHandler client : clientList) {
|
||||||
if (!client.equals(fromClient)) {
|
if (!client.equals(fromClient)) {
|
||||||
|
|
@ -463,6 +602,11 @@ public class ChatServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attente d'une chaine de caractères en entrée.
|
||||||
|
* @return chaine de caractères reçue
|
||||||
|
* @throws IOException lorsque la fin du flux est atteinte
|
||||||
|
*/
|
||||||
public String receive() throws IOException {
|
public String receive() throws IOException {
|
||||||
String message = in.readLine();
|
String message = in.readLine();
|
||||||
LOGGER.info("receive: %s".formatted(message));
|
LOGGER.info("receive: %s".formatted(message));
|
||||||
|
|
@ -472,6 +616,9 @@ public class ChatServer {
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ferme la connexion TCP
|
||||||
|
*/
|
||||||
public void close() {
|
public void close() {
|
||||||
LOGGER.info("[%s] Fermeture de la connexion".formatted(ipPort));
|
LOGGER.info("[%s] Fermeture de la connexion".formatted(ipPort));
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue