From a3873394be2c23eaba850bc04a349fee5465c362 Mon Sep 17 00:00:00 2001 From: Arnaud Vergnet Date: Mon, 4 Jan 2021 20:51:05 +0100 Subject: [PATCH] improve database compatibility with UI --- .../fr/insa/clavardator/chat/ChatHistory.java | 5 +- .../fr/insa/clavardator/chat/Message.java | 9 ++ .../clavardator/db/DatabaseController.java | 108 ++++++++++++++---- .../insa/clavardator/ui/MainController.java | 28 +++-- .../ui/chat/MessageListItemController.java | 2 +- .../ui/users/UserListController.java | 14 ++- .../insa/clavardator/users/CurrentUser.java | 51 ++++++--- .../java/fr/insa/clavardator/users/User.java | 4 + 8 files changed, 165 insertions(+), 56 deletions(-) diff --git a/src/main/java/fr/insa/clavardator/chat/ChatHistory.java b/src/main/java/fr/insa/clavardator/chat/ChatHistory.java index c096d1c..1e3b06f 100644 --- a/src/main/java/fr/insa/clavardator/chat/ChatHistory.java +++ b/src/main/java/fr/insa/clavardator/chat/ChatHistory.java @@ -53,7 +53,10 @@ public class ChatHistory { * Loads history from database */ public void load() { - db.getChatHistory(new UserInformation(user), new Date(), new Date(), this::onLoaded); + final Date from = new Date(); + // Load whole history + from.setTime(0); + db.getChatHistory(new UserInformation(user), from, new Date(), this::onLoaded); } /** diff --git a/src/main/java/fr/insa/clavardator/chat/Message.java b/src/main/java/fr/insa/clavardator/chat/Message.java index 2c2cdf9..dd64b93 100644 --- a/src/main/java/fr/insa/clavardator/chat/Message.java +++ b/src/main/java/fr/insa/clavardator/chat/Message.java @@ -1,5 +1,6 @@ package fr.insa.clavardator.chat; +import fr.insa.clavardator.users.CurrentUser; import fr.insa.clavardator.users.User; import fr.insa.clavardator.users.UserInformation; @@ -46,6 +47,14 @@ public class Message implements Serializable { return recipient; } + public UserInformation getCorrespondent() { + if (CurrentUser.getInstance().isLocalId(sender.id)) { + return recipient; + } else { + return sender; + } + } + public Date getDate() { return date; } diff --git a/src/main/java/fr/insa/clavardator/db/DatabaseController.java b/src/main/java/fr/insa/clavardator/db/DatabaseController.java index a50638f..95cca02 100644 --- a/src/main/java/fr/insa/clavardator/db/DatabaseController.java +++ b/src/main/java/fr/insa/clavardator/db/DatabaseController.java @@ -2,10 +2,12 @@ package fr.insa.clavardator.db; import fr.insa.clavardator.chat.FileMessage; import fr.insa.clavardator.chat.Message; +import fr.insa.clavardator.users.CurrentUser; import fr.insa.clavardator.users.User; import fr.insa.clavardator.users.UserInformation; import fr.insa.clavardator.util.Log; import org.intellij.lang.annotations.Language; +import org.jetbrains.annotations.Nullable; import java.sql.*; import java.util.ArrayList; @@ -31,7 +33,6 @@ public class DatabaseController { */ public void connect() { connectToDatabase("clavardator"); - initTables(); } /** @@ -103,16 +104,19 @@ public class DatabaseController { Log.v(getClass().getSimpleName(), "Creating table user..."); executeUpdate("CREATE TABLE IF NOT EXISTS user " + "(id INTEGER UNSIGNED PRIMARY KEY NOT NULL," + - " username TINYTEXT NOT NULL)"); + " username TINYTEXT NULLABLE )"); } /** * Creates all needed tables if non-existent */ - private void initTables() { + public void init(@Nullable FinishCallback callback) { try { createMessageTable(); createUserTable(); + if (callback != null) { + callback.onFinish(); + } } catch (SQLException e) { e.printStackTrace(); } @@ -153,7 +157,7 @@ public class DatabaseController { */ public void resetTables() { dropTables(); - initTables(); + init(null); } @@ -165,7 +169,7 @@ public class DatabaseController { public void getAllUsers(UsersCallback callback) { try { Statement stmt = connection.createStatement(); - String sql = "SELECT * FROM user"; + String sql = "SELECT * FROM user WHERE id != " + CurrentUser.getInstance().getId(); Log.v(getClass().getSimpleName(), "Fetching users from db... "); ResultSet res = stmt.executeQuery(sql); @@ -196,7 +200,7 @@ public class DatabaseController { * @param message The message to add to the database * @param callback Function called when the request is done */ - public void addMessage(Message message, MessageCallback callback) { + public void addMessage(Message message, FinishCallback callback) { try { // TODO: Handle messages containing files: // store file in file system and put the path in filePath @@ -208,42 +212,67 @@ public class DatabaseController { // Insert the new message Log.v(getClass().getSimpleName(), "Inserting message into db... "); + + int recipientId; + int senderId; + if (CurrentUser.getInstance().isLocalId(message.getRecipient().id)) { + recipientId = CurrentUser.getInstance().getId(); + senderId = message.getSender().id; + } else { + senderId = CurrentUser.getInstance().getId(); + recipientId = message.getRecipient().id; + } + executeUpdate("INSERT INTO message " + "(timestamp, sender, recipient, text, file_path) " + "VALUES (" + message.getDate().getTime() + ", " + - message.getSender().id + ", " + - message.getRecipient().id + ", " + + senderId + ", " + + recipientId + ", " + "\"" + message.getText() + "\", " + filePath + ")"); - // Insert the sender - Log.v(getClass().getSimpleName(), "Inserting sender into db... "); - addUser(message.getSender()); + Log.v(getClass().getSimpleName(), "Inserting correspondent into db... "); + addUser(message.getCorrespondent()); - // Insert the recipient - Log.v(getClass().getSimpleName(), "Inserting recipient into db... "); - addUser(message.getRecipient()); if (callback != null) { - callback.onMessageSaved(); + callback.onFinish(); } } catch (SQLException e) { e.printStackTrace(); } } + public void addUser(UserInformation user) { + addUser(user, null); + } + /** * Inserts the given user if not existing * * @param user The user information to store - * @throws SQLException SQL error */ - private void addUser(UserInformation user) throws SQLException { - executeUpdate("INSERT OR IGNORE INTO user " + - "(id, username) " + - "VALUES (" + user.id + ", \"" + user.getUsername() + "\")"); + public void addUser(UserInformation user, @Nullable FinishCallback callback) { + try { + Log.v(getClass().getSimpleName(), "Adding user to db: " + user.id + " / " + user.getUsername()); + if (user.getUsername() != null) { + executeUpdate("INSERT OR IGNORE INTO user " + + "(id, username) " + + "VALUES (" + user.id + ", \"" + user.getUsername() + "\")"); + } else { + executeUpdate("INSERT OR IGNORE INTO user " + + "(id) " + + "VALUES (" + user.id + ")"); + } + + if (callback != null) { + callback.onFinish(); + } + } catch (SQLException e) { + e.printStackTrace(); + } } /** @@ -296,16 +325,51 @@ public class DatabaseController { } } + public void updateUsername(UserInformation user) { + try { + executeUpdate("UPDATE user SET " + + "username = '" + user.getUsername() + "' where id = " + user.id); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public void getUsername(int id, UsernameCallback callback) { + try { + Statement statement = connection.createStatement(); + String sql = "SELECT username from user where id =" + id; + + Log.v(getClass().getSimpleName(), "Fetching users from db... "); + ResultSet res = statement.executeQuery(sql); + + String username = null; + if (res.next()) { + username = res.getString("username"); + } + Log.v(getClass().getSimpleName(), res.getFetchSize() + " rows fetched"); + res.close(); + statement.close(); + if (callback != null) { + callback.onUsernameFetched(username); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } public interface UsersCallback { void onUsersFetched(ArrayList users); } + public interface UsernameCallback { + void onUsernameFetched(String username); + } + public interface HistoryCallback { void onHistoryFetched(ArrayList history); } - public interface MessageCallback { - void onMessageSaved(); + public interface FinishCallback { + void onFinish(); } } diff --git a/src/main/java/fr/insa/clavardator/ui/MainController.java b/src/main/java/fr/insa/clavardator/ui/MainController.java index 5115618..94316c7 100644 --- a/src/main/java/fr/insa/clavardator/ui/MainController.java +++ b/src/main/java/fr/insa/clavardator/ui/MainController.java @@ -1,6 +1,7 @@ package fr.insa.clavardator.ui; import com.jfoenix.controls.JFXSnackbar; +import fr.insa.clavardator.db.DatabaseController; import fr.insa.clavardator.ui.chat.ChatController; import fr.insa.clavardator.ui.dialogs.AboutDialogController; import fr.insa.clavardator.ui.dialogs.EditUsernameDialogController; @@ -64,7 +65,7 @@ public class MainController implements Initializable { if (historyLoaded) { if (newState == CurrentUser.State.VALID) startChat(); - else if (newState != CurrentUser.State.NONE) { + else if (newState != CurrentUser.State.UNINITIALIZED) { final boolean isError = newState == CurrentUser.State.INVALID; if (isError) { endChat(); @@ -78,7 +79,7 @@ public class MainController implements Initializable { historyLoaded = true; final CurrentUser.State userState = CurrentUser.getInstance().getState(); // If the history loaded after the current user, fire the state change event again - if (userState != CurrentUser.State.NONE) { + if (userState != CurrentUser.State.UNINITIALIZED) { onCurrentUserStateChange(userState); } } @@ -191,14 +192,6 @@ public class MainController implements Initializable { loadingController.show("Initialisation de Clavardator..."); snackbar = new JFXSnackbar(root); - try { - currentUser.init(); - Log.v("INIT", "Current user: " + currentUser.getId()); - } catch (SocketException e) { - Log.e("INIT", "Could not init user", e); - showError(); - } - listController.setUserSelectedListener((user) -> chatController.setRemoteUser(user)); chatController.addAttachmentListener(() -> System.out.println("attach event")); chatController.addSendErrorListener((e) -> showSnackbarEvent("Erreur: Message non envoyé", SnackbarController.Mode.ERROR)); @@ -206,11 +199,24 @@ public class MainController implements Initializable { toolbarController.addAboutListener(this::openAboutDialog); } + private void initDb() { + final DatabaseController db = new DatabaseController(); + db.init(() -> { + try { + Log.v("INIT", "Current user: " + currentUser.getId()); + currentUser.init(() -> userList.retrievedPreviousUsers(this::onHistoryLoaded)); + } catch (SocketException e) { + Log.e("INIT", "Could not init user", e); + showError(); + } + }); + } + public void setUserList(UserList userList) { this.userList = userList; - userList.retrievedPreviousUsers(this::onHistoryLoaded); listController.setUserList(userList); listController.setRefreshUserListener(this::discoverActiveUsers); editUserDialogController.setUserList(userList); + initDb(); } } diff --git a/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemController.java b/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemController.java index cffaf1a..c091b8e 100644 --- a/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemController.java +++ b/src/main/java/fr/insa/clavardator/ui/chat/MessageListItemController.java @@ -34,7 +34,7 @@ public class MessageListItemController implements Initializable { currentMessage = message; button.setText(message.getText()); timestamp.setText(DateFormat.getTimeInstance().format(message.getDate())); - if (message.getSender().id == CurrentUser.getInstance().getId()) { + if (CurrentUser.getInstance().isLocalId(message.getSender().id)) { container.setAlignment(Pos.CENTER_RIGHT); button.getStyleClass().remove("message-other"); button.getStyleClass().add("message-self"); diff --git a/src/main/java/fr/insa/clavardator/ui/users/UserListController.java b/src/main/java/fr/insa/clavardator/ui/users/UserListController.java index 9d0a1eb..4d30e8e 100644 --- a/src/main/java/fr/insa/clavardator/ui/users/UserListController.java +++ b/src/main/java/fr/insa/clavardator/ui/users/UserListController.java @@ -55,12 +55,14 @@ public class UserListController implements Initializable { } private void onUserConnected(PeerUser user) { - if (!peerUserListView.getItems().contains(user)) { - Log.v(this.getClass().getSimpleName(), "Add user to UI"); - Platform.runLater(() -> peerUserListView.getItems().add(user)); - } else { - Log.w(this.getClass().getSimpleName(), "User already added to ui, skipping..."); - } + Platform.runLater(() -> { + if (!peerUserListView.getItems().contains(user)) { + Log.v(this.getClass().getSimpleName(), "Add user to UI"); + peerUserListView.getItems().add(user); + } else { + Log.w(this.getClass().getSimpleName(), "User already added to ui, skipping..."); + } + }); } public void setUserList(UserList userList) { diff --git a/src/main/java/fr/insa/clavardator/users/CurrentUser.java b/src/main/java/fr/insa/clavardator/users/CurrentUser.java index 347d518..981b520 100644 --- a/src/main/java/fr/insa/clavardator/users/CurrentUser.java +++ b/src/main/java/fr/insa/clavardator/users/CurrentUser.java @@ -1,14 +1,13 @@ package fr.insa.clavardator.users; +import fr.insa.clavardator.db.DatabaseController; import fr.insa.clavardator.network.NetUtil; import fr.insa.clavardator.util.Log; -import javafx.application.Platform; import java.net.InetAddress; import java.net.SocketException; +import java.util.ArrayList; import java.util.List; -import java.util.Timer; -import java.util.TimerTask; import static fr.insa.clavardator.network.NetUtil.getIdFromIp; @@ -17,9 +16,12 @@ public class CurrentUser extends User { private State state; + private ArrayList validIds; + private CurrentUser() { super(); state = State.UNINITIALIZED; + validIds = new ArrayList<>(); } /** @@ -31,22 +33,33 @@ public class CurrentUser extends User { return instance; } - public void init() throws SocketException { + public void init(InitCallback callback) throws SocketException { final List addresses = NetUtil.listAllLocalAddresses(); - if (addresses.size() > 0) { - id = getIdFromIp(addresses.get(0)); + // Save all addresses for this user + validIds = new ArrayList<>(); + addresses.forEach(address -> validIds.add(getIdFromIp(address))); + if (validIds.size() > 0) { + // Set the first id as the main one + id = validIds.get(0); } else { throw new SocketException(); } - // TODO replace by db username fetching - Timer t = new Timer(); - t.schedule(new TimerTask() { - @Override - public void run() { - setState(State.NONE); - t.cancel(); - } - }, 500); + final DatabaseController db = new DatabaseController(); + // Make sure the user is in the db then set its username + db.addUser(new UserInformation(this), () -> { + db.getUsername(id, username -> { + if (username != null) { + Log.v(getClass().getSimpleName(), "Last username found : " + username); + setUsername(username); + } else { + Log.v(getClass().getSimpleName(), "No last username found, asking user..."); + setState(State.NONE); + } + if (callback != null) { + callback.onFinish(); + } + }); + }); } @Override @@ -68,10 +81,18 @@ public class CurrentUser extends User { return state; } + public boolean isLocalId(int id) { + return validIds.contains(id); + } + public enum State { UNINITIALIZED, VALID, INVALID, NONE } + + public interface InitCallback { + void onFinish(); + } } diff --git a/src/main/java/fr/insa/clavardator/users/User.java b/src/main/java/fr/insa/clavardator/users/User.java index 263f202..7bc45cc 100644 --- a/src/main/java/fr/insa/clavardator/users/User.java +++ b/src/main/java/fr/insa/clavardator/users/User.java @@ -1,5 +1,7 @@ package fr.insa.clavardator.users; +import fr.insa.clavardator.db.DatabaseController; + import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.Serializable; @@ -41,6 +43,8 @@ public class User implements Serializable { protected void setUsername(String newUsername) { pcs.firePropertyChange("username", this.username, newUsername); this.username = newUsername; + final DatabaseController db = new DatabaseController(); + db.updateUsername(new UserInformation(this)); } @Override