make DatabaseController async

This commit is contained in:
Yohan Simard 2021-01-05 15:34:24 +01:00
parent 6d3971be40
commit 1ab27f4f87
9 changed files with 359 additions and 258 deletions

View file

@ -3,6 +3,7 @@ package fr.insa.clavardator.chat;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.users.PeerUser;
import fr.insa.clavardator.users.UserInformation;
import fr.insa.clavardator.util.ErrorCallback;
import fr.insa.clavardator.util.Log;
import javafx.application.Platform;
import javafx.collections.FXCollections;
@ -44,12 +45,12 @@ public class ChatHistory {
/**
* Loads history from database only if it has not previously been loaded
*/
public void load() {
public void load(ErrorCallback errorCallback) {
if (!historyLoaded) {
final Date from = new Date();
// Load whole history
from.setTime(0);
db.getChatHistory(new UserInformation(user), from, new Date(), this::onLoaded);
db.getChatHistory(new UserInformation(user), from, new Date(), this::onLoaded, errorCallback);
} else {
notifyHistoryLoaded();
}
@ -77,10 +78,10 @@ public class ChatHistory {
*
* @param message The message to add
*/
public void addMessage(Message message) {
public void addMessage(Message message, ErrorCallback errorCallback) {
db.addMessage(message, () -> {
Platform.runLater(() -> history.add(message));
});
}, errorCallback);
}
public interface HistoryLoadedCallback {

View file

@ -5,6 +5,7 @@ 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.ErrorCallback;
import fr.insa.clavardator.util.Log;
import org.intellij.lang.annotations.Language;
import org.jetbrains.annotations.Nullable;
@ -21,7 +22,7 @@ public class DatabaseController {
}
public DatabaseController(boolean test) {
if(test) {
if (test) {
connectToTestDb();
} else {
connect();
@ -31,20 +32,22 @@ public class DatabaseController {
/**
* Connects to the main database
*/
public void connect() {
private void connect() {
connectToDatabase("clavardator");
}
/**
* Connects to the test database.
* @implNote DO NOT USE OUTSIDE OF TESTS
*
* @implNote DO NOT USE OUTSIDE OF TESTS
*/
public void connectToTestDb() {
private void connectToTestDb() {
connectToDatabase("clavardator_test");
}
/**
* Connects to the database of the given name
*
* @param dbName The database to connect to
*/
private void connectToDatabase(String dbName) {
@ -68,128 +71,122 @@ public class DatabaseController {
}
}
/**
* Executes a simple update statement
*
* @param sqlQuery The query to execute
* @throws SQLException SQL error
*/
private void executeUpdate(@Language("SQL") String sqlQuery) throws SQLException {
Statement statement = connection.createStatement();
final int rowsModified = statement.executeUpdate(sqlQuery);
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
statement.close();
}
/**
* Creates the table used to store messages
* @throws SQLException SQL error
*
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
private void createMessageTable() throws SQLException {
Log.v(getClass().getSimpleName(), "Creating table message...");
executeUpdate("CREATE TABLE IF NOT EXISTS message " +
private void createMessageTable(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "CREATE TABLE IF NOT EXISTS message " +
"(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
" timestamp DATETIME NOT NULL, " +
" sender INTEGER UNSIGNED NOT NULL, " +
" recipient INTEGER UNSIGNED NOT NULL, " +
" text TEXT, " +
" file_path TEXT)");
" file_path TEXT)";
Log.v(getClass().getSimpleName(), "Creating table message...");
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}
/**
* Creates the table used to store users
* @throws SQLException SQL error
*
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
private void createUserTable() throws SQLException {
Log.v(getClass().getSimpleName(), "Creating table user...");
executeUpdate("CREATE TABLE IF NOT EXISTS user " +
private void createUserTable(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "CREATE TABLE IF NOT EXISTS user " +
"(id INTEGER UNSIGNED PRIMARY KEY NOT NULL," +
" username TINYTEXT NULLABLE )");
" username TINYTEXT NULLABLE )";
Log.v(getClass().getSimpleName(), "Creating table user...");
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}
/**
* Creates all needed tables if non-existent
*
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
public void init(@Nullable FinishCallback callback) {
try {
createMessageTable();
createUserTable();
if (callback != null) {
callback.onFinish();
}
} catch (SQLException e) {
e.printStackTrace();
}
public void initTables(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
createMessageTable(() -> createUserTable(callback, errorCallback), errorCallback);
}
/**
* Destroys the message table
* @throws SQLException SQL error
*
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
private void dropMessageTable() throws SQLException {
private void dropMessageTable(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "DROP TABLE IF EXISTS message";
Log.v(getClass().getSimpleName(), "Dropping table message...");
executeUpdate("DROP TABLE IF EXISTS message");
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}
/**
* Destroys the user table
* @throws SQLException SQL error
*
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
private void dropUserTable() throws SQLException {
private void dropUserTable(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "DROP TABLE IF EXISTS user";
Log.v(getClass().getSimpleName(), "Dropping table user...");
executeUpdate("DROP TABLE IF EXISTS user");
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}
/**
* Destroys all tables
*
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
private void dropTables() {
try {
dropMessageTable();
dropUserTable();
} catch (SQLException e) {
e.printStackTrace();
}
private void dropTables(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
dropMessageTable(() -> dropUserTable(callback, errorCallback), errorCallback);
}
/**
* Destroys and recreates all tables
*
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
public void resetTables() {
dropTables();
init(null);
public void resetTables(@Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
dropTables(() -> initTables(callback, errorCallback), errorCallback);
}
/**
* Fetches the list of users for which we already have a chat history
*
* @param callback Function called when the request is done
* @param callback Function called when the request is done
* @param errorCallback The function to call on error
*/
public void getAllUsers(UsersCallback callback) {
try {
Statement stmt = connection.createStatement();
String sql = "SELECT * FROM user WHERE id != " + CurrentUser.getInstance().getId();
public void getAllUsers(UsersCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "SELECT * FROM user WHERE id != " + CurrentUser.getInstance().getId();
Log.v(getClass().getSimpleName(), "Fetching users from db... ");
ResultSet res = stmt.executeQuery(sql);
Log.v(getClass().getSimpleName(), "Fetching users from db... ");
QueryExecutor executor = new QueryExecutor(sql, res -> {
ArrayList<User> userList = new ArrayList<>();
while (res.next()) {
int id = res.getInt("id");
String username = res.getString("username");
userList.add(new User(id, username));
}
Log.v(getClass().getSimpleName(), userList.size() + " rows fetched");
res.close();
stmt.close();
Log.v(getClass().getSimpleName(), userList.size() + " users fetched");
if (callback != null) {
callback.onUsersFetched(userList);
}
} catch (SQLException e) {
e.printStackTrace();
}
callback.onUsersFetched(userList);
}, errorCallback);
executor.start();
}
@ -197,33 +194,37 @@ public class DatabaseController {
* Adds a message to the database for this user.
* If the user does not exist, we create it.
*
* @param message The message to add to the database
* @param callback Function called when the request is done
* @param message The message to add to the database
* @param callback Function called when the request is done
* @param errorCallback The function to call on error
*/
public void addMessage(Message message, FinishCallback callback) {
try {
public void addMessage(Message message, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
// Insert the correspondent if not already in the database
Log.v(getClass().getSimpleName(), "Inserting correpondent into db... ");
addUser(message.getCorrespondent(), () -> {
// Handle messages containing a file
String filePath = "NULL";
// TODO: Handle messages containing files:
// store file in file system and put the path in filePath
String filePath = "NULL";
if (message instanceof FileMessage) {
Log.w(getClass().getSimpleName(), "Functionality not implemented: file has not been saved");
// filePath = ((FileMessage) message).getFileName();
}
// Insert the new message
Log.v(getClass().getSimpleName(), "Inserting message into db... ");
// TODO: do this in the construction of the message instead?
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;
}
// 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 " +
// Insert the new message
@Language("SQL") String sql = "INSERT INTO message " +
"(timestamp, sender, recipient, text, file_path) " +
"VALUES (" +
message.getDate().getTime() + ", " +
@ -231,73 +232,57 @@ public class DatabaseController {
recipientId + ", " +
"\"" + message.getText() + "\", " +
filePath +
")");
")";
Log.v(getClass().getSimpleName(), "Inserting message into db... ");
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
Log.v(getClass().getSimpleName(), "Inserting correspondent into db... ");
addUser(message.getCorrespondent());
if (callback != null) {
callback.onFinish();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public void addUser(UserInformation user) {
addUser(user, null);
}, errorCallback);
}
/**
* Inserts the given user if not existing
*
* @param user The user information to store
* @param user The user information to store
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
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();
public void addUser(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql;
if (user.getUsername() != null) {
sql = "INSERT OR IGNORE INTO user (id, username) " +
"VALUES (" + user.id + ", \"" + user.getUsername() + "\")";
} else {
sql = "INSERT OR IGNORE INTO user (id) " +
"VALUES (" + user.id + ")";
}
Log.v(getClass().getSimpleName(), "Adding user to db: " + user.id + " / " + user.getUsername());
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}
/**
* Gets the chat history for a given time frame
*
* @param user the user for which to retrieve the history
* @param from the starting date
* @param to the ending date
* @param callback Function called when the request is done
* @param user the user for which to retrieve the history
* @param from the starting date
* @param to the ending date
* @param callback Function called when the request is done
* @param errorCallback The function to call on error
*/
public void getChatHistory(UserInformation user, Date from, Date to, HistoryCallback callback) {
try {
Statement stmt = connection.createStatement();
String sql =
"SELECT timestamp, s.id AS sender_id, s.username AS sender_username, " +
"r.id AS recipient_id, r.username AS recipient_username, text, file_path " +
"FROM message JOIN user AS s ON sender = s.id " +
" JOIN user AS r ON recipient = r.id " +
"WHERE (s.id = " + user.id + " OR r.id = " + user.id + ") AND " +
"timestamp > " + from.getTime() + " AND timestamp < " + to.getTime() + " " +
"ORDER BY timestamp";
Log.v(getClass().getSimpleName(), "Fetching chat history from db... ");
ResultSet res = stmt.executeQuery(sql);
public void getChatHistory(UserInformation user, Date from, Date to, HistoryCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql =
"SELECT timestamp, s.id AS sender_id, s.username AS sender_username, " +
"r.id AS recipient_id, r.username AS recipient_username, text, file_path " +
"FROM message JOIN user AS s ON sender = s.id " +
" JOIN user AS r ON recipient = r.id " +
"WHERE (s.id = " + user.id + " OR r.id = " + user.id + ") AND " +
"timestamp > " + from.getTime() + " AND timestamp < " + to.getTime() + " " +
"ORDER BY timestamp";
Log.v(getClass().getSimpleName(), "Fetching chat history from db... ");
QueryExecutor executor = new QueryExecutor(sql, res -> {
ArrayList<Message> chatHistory = new ArrayList<>();
while (res.next()) {
int sId = res.getInt("sender_id");
@ -314,49 +299,107 @@ public class DatabaseController {
// chatHistory.add(new FileMessage(new UserInformation(sId, sUsername), new UserInformation(rId, rUsername), date, text, filePath));
}
}
Log.v(getClass().getSimpleName(), chatHistory.size() + " rows fetched");
res.close();
stmt.close();
if (callback != null) {
callback.onHistoryFetched(chatHistory);
}
} catch (SQLException e) {
e.printStackTrace();
}
Log.v(getClass().getSimpleName(), chatHistory.size() + " messages fetched");
callback.onHistoryFetched(chatHistory);
}, errorCallback);
executor.start();
}
public void updateUsername(UserInformation user) {
try {
executeUpdate("UPDATE user SET " +
"username = '" + user.getUsername() + "' where id = " + user.id);
} catch (SQLException e) {
e.printStackTrace();
}
public void updateUsername(UserInformation user, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "UPDATE user SET username = '" + user.getUsername() + "' where id = " + user.id;
UpdateExecutor executor = new UpdateExecutor(sql, callback, errorCallback);
executor.start();
}
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);
public void getUsername(int id, UsernameCallback callback, ErrorCallback errorCallback) {
@Language("SQL") String sql = "SELECT username from user where id =" + id;
Log.v(getClass().getSimpleName(), "Fetching username from db... ");
QueryExecutor executor = new QueryExecutor(sql, res -> {
String username = null;
int nbRows = 0;
if (res.next()) {
username = res.getString("username");
nbRows = 1;
}
Log.v(getClass().getSimpleName(), res.getFetchSize() + " rows fetched");
res.close();
statement.close();
if (callback != null) {
callback.onUsernameFetched(username);
Log.v(getClass().getSimpleName(), nbRows + " username fetched");
callback.onUsernameFetched(username);
}, errorCallback);
executor.start();
}
private class UpdateExecutor extends Thread {
private final String sqlQuery;
private final UpdateCallback callback;
private final ErrorCallback errorCallback;
/**
* Constructs a thread that executes an update on the database
*
* @param sqlQuery The query to execute
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
public UpdateExecutor(@Language("SQL") String sqlQuery, @Nullable DatabaseController.UpdateCallback callback, ErrorCallback errorCallback) {
this.sqlQuery = sqlQuery;
this.callback = callback;
this.errorCallback = errorCallback;
}
@Override
public void run() {
try {
Statement statement = connection.createStatement();
final int rowsModified = statement.executeUpdate(sqlQuery);
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
statement.close();
if (callback != null) {
callback.onUpdateExecuted();
}
} catch (SQLException e) {
Log.e(this.getClass().getSimpleName(), "Error executing update: ", e);
errorCallback.onError(e);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private class QueryExecutor extends Thread {
private final String sqlQuery;
private final QueryCallback callback;
private final ErrorCallback errorCallback;
/**
* Constructs a thread that executes an update on the database
*
* @param sqlQuery The query to execute
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
public QueryExecutor(@Language("SQL") String sqlQuery, @Nullable QueryCallback callback, ErrorCallback errorCallback) {
this.sqlQuery = sqlQuery;
this.callback = callback;
this.errorCallback = errorCallback;
}
@Override
public void run() {
try {
Statement statement = connection.createStatement();
final ResultSet resultSet = statement.executeQuery(sqlQuery);
if (callback != null) {
callback.onQueryExecuted(resultSet);
}
resultSet.close();
statement.close();
} catch (SQLException e) {
Log.e(this.getClass().getSimpleName(), "Error executing update: ", e);
errorCallback.onError(e);
}
}
}
public interface UsersCallback {
void onUsersFetched(ArrayList<User> users);
}
@ -369,7 +412,11 @@ public class DatabaseController {
void onHistoryFetched(ArrayList<Message> history);
}
public interface FinishCallback {
void onFinish();
public interface UpdateCallback {
void onUpdateExecuted();
}
private interface QueryCallback {
void onQueryExecuted(ResultSet resultSet) throws SQLException;
}
}

View file

@ -17,7 +17,6 @@ import javafx.fxml.Initializable;
import javafx.scene.layout.StackPane;
import java.io.IOException;
import java.net.SocketException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Timer;
@ -262,20 +261,22 @@ public class MainController implements Initializable {
toolbarController.setAboutListener(this::openAboutDialog);
}
private void onInitError(Exception e) {
Log.e("INIT", "Error during initialization", e);
showError();
}
/**
* Creates database if needed, then init current user, and finally load user list
*/
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();
}
});
db.initTables(() -> {
Log.v("INIT", "Current user: " + currentUser.getId());
currentUser.init(() -> {
userList.retrievedPreviousUsers(this::onHistoryLoaded, this::onInitError);
}, this::onInitError);
}, this::onInitError);
}
/**

View file

@ -7,6 +7,7 @@ import fr.insa.clavardator.ui.LoadingScreenController;
import fr.insa.clavardator.ui.NoSelectionModel;
import fr.insa.clavardator.users.PeerUser;
import fr.insa.clavardator.util.ErrorCallback;
import fr.insa.clavardator.util.Log;
import javafx.application.Platform;
import javafx.collections.ListChangeListener;
import javafx.fxml.FXML;
@ -73,7 +74,7 @@ public class ChatController implements Initializable {
// Make sure we always have the latest item on screen
scrollToEnd();
});
history.load();
history.load(e -> Log.e(getClass().getSimpleName(), "Error while loading message", e)/* TODO: show an error message? */);
}
/**

View file

@ -2,7 +2,9 @@ package fr.insa.clavardator.users;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.network.NetUtil;
import fr.insa.clavardator.util.ErrorCallback;
import fr.insa.clavardator.util.Log;
import org.jetbrains.annotations.Nullable;
import java.net.InetAddress;
import java.net.SocketException;
@ -33,33 +35,38 @@ public class CurrentUser extends User {
return instance;
}
public void init(InitCallback callback) throws SocketException {
final List<InetAddress> addresses = NetUtil.listAllLocalAddresses();
// 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();
public void init(@Nullable InitCallback callback, ErrorCallback errorCallback) {
try {
final List<InetAddress> addresses = NetUtil.listAllLocalAddresses();
// 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 {
errorCallback.onError(new SocketException("No valid IP found"));
return;
}
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();
}
}, errorCallback);
}, errorCallback);
} catch (SocketException e) {
errorCallback.onError(e);
}
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

View file

@ -76,10 +76,7 @@ public class PeerUser extends User implements Comparable<PeerUser> {
Log.v(this.getClass().getSimpleName(),
"Sending message to " + this.getUsername() + " / " + this.getId() + ": " + msg);
final Message message = new Message(CurrentUser.getInstance(), this, new Date(), msg);
connection.send(
message,
() -> history.addMessage(message),
errorCallback);
connection.send(message, () -> history.addMessage(message, errorCallback), errorCallback);
} else {
Log.e(this.getClass().getSimpleName(), "Could not send message: connection is not initialized");
}
@ -175,8 +172,10 @@ public class PeerUser extends User implements Comparable<PeerUser> {
}
} else if (msg instanceof Message) {
assert ((Message) msg).getRecipient().id != id;
assert CurrentUser.getInstance().isLocalId(((Message) msg).getRecipient().id);
Log.v(this.getClass().getSimpleName(), "Message text: " + ((Message) msg).getText());
history.addMessage((Message) msg);
history.addMessage((Message) msg, errorCallback);
} else if (msg instanceof UsernameTakenException) {
disconnect();
errorCallback.onError(new Exception("Received username already taken message"));

View file

@ -1,6 +1,7 @@
package fr.insa.clavardator.users;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.util.Log;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
@ -44,7 +45,7 @@ public class User implements Serializable {
pcs.firePropertyChange("username", this.username, newUsername);
this.username = newUsername;
final DatabaseController db = new DatabaseController();
db.updateUsername(new UserInformation(this));
db.updateUsername(new UserInformation(this), null, e -> Log.e(getClass().getSimpleName(), "Unable to update the username", e));
}
@Override

View file

@ -7,7 +7,6 @@ import fr.insa.clavardator.util.ErrorCallback;
import fr.insa.clavardator.util.Log;
import java.beans.PropertyChangeEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Predicate;
@ -78,11 +77,11 @@ public class UserList {
Throwable::printStackTrace);
}
public void retrievedPreviousUsers(UserListLoadedCallback onFinish) {
public void retrievedPreviousUsers(UserListLoadedCallback onFinish, ErrorCallback errorCallback) {
db.getAllUsers(users -> {
users.forEach(user -> createNewUser(user.id, user.getUsername()));
onFinish.onLoaded();
});
}, errorCallback);
}
/**

View file

@ -3,56 +3,101 @@ package fr.insa.clavardator;
import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.users.UserInformation;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;
public class DatabaseTest {
private final DatabaseController db = new DatabaseController(true);
@Test
void testDB() {
db.resetTables();
db.getAllUsers(users -> {
assertEquals(0, users.size());
assertTimeoutPreemptively(Duration.ofSeconds(1), () -> {
CountDownLatch latch1 = new CountDownLatch(1);
db.resetTables(latch1::countDown, Assertions::fail);
latch1.await();
CountDownLatch latch2 = new CountDownLatch(2);
db.getAllUsers(users -> {
assertEquals(0, users.size());
latch2.countDown();
}, Assertions::fail);
db.getChatHistory(new UserInformation(1, "Yohan"), new Date(0), new Date(), history -> {
assertEquals(history.size(), 0);
latch2.countDown();
}, Assertions::fail);
latch2.await();
CountDownLatch latch8 = new CountDownLatch(1);
db.addUser(new UserInformation(3, null), latch8::countDown, Assertions::fail);
latch8.await();
CountDownLatch latch3 = new CountDownLatch(5);
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"),
new Date(1609843556860L), "Coucou Arnaud !"), latch3::countDown, Assertions::fail);
db.addMessage(new Message(new UserInformation(2, "Arnaud"), new UserInformation(1, "Yohan"),
new Date(1609843556861L), "Coucou Yohan !"), latch3::countDown, Assertions::fail);
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"),
new Date(1609843556862L), "Ça va ?"), latch3::countDown, Assertions::fail);
db.addMessage(new Message(new UserInformation(2, "Arnaud"), new UserInformation(1, "Yohan"),
new Date(1609843556863L), "Ouais et toi ?"), latch3::countDown, Assertions::fail);
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"),
new Date(1609843556864L), "Super !"), latch3::countDown, Assertions::fail);
latch3.await();
CountDownLatch latch4 = new CountDownLatch(2);
db.getAllUsers(users -> {
assertEquals(3, users.size());
assertEquals(3, users.get(0).getId());
assertEquals(1, users.get(1).getId());
assertEquals(2, users.get(2).getId());
assertNull(users.get(0).getUsername());
assertEquals("Yohan", users.get(1).getUsername());
assertEquals("Arnaud", users.get(2).getUsername());
latch4.countDown();
}, Assertions::fail);
db.getChatHistory(new UserInformation(1, "Yohan"), new Date(0), new Date(), history -> {
assertEquals(5, history.size());
assertEquals("Coucou Arnaud !", history.get(0).getText());
assertEquals(1, history.get(0).getSender().id);
assertEquals(2, history.get(0).getRecipient().id);
assertEquals("Yohan", history.get(0).getSender().getUsername());
assertEquals("Arnaud", history.get(0).getRecipient().getUsername());
assertEquals("Ouais et toi ?", history.get(3).getText());
assertEquals(2, history.get(3).getSender().id);
assertEquals(1, history.get(3).getRecipient().id);
assertEquals("Arnaud", history.get(3).getSender().getUsername());
assertEquals("Yohan", history.get(3).getRecipient().getUsername());
latch4.countDown();
}, Assertions::fail);
latch4.await();
CountDownLatch latch5 = new CountDownLatch(1);
db.updateUsername(new UserInformation(2, "Toto"), latch5::countDown, Assertions::fail);
latch5.await();
CountDownLatch latch6 = new CountDownLatch(1);
db.getUsername(2, username -> {
assertEquals("Toto", username);
latch6.countDown();
}, Assertions::fail);
latch6.await();
CountDownLatch latch7 = new CountDownLatch(1);
db.resetTables(latch7::countDown, Assertions::fail);
latch7.await();
db.close();
});
db.getChatHistory(new UserInformation(1, "Yohan"), new Date(0), new Date(), history -> {
assertEquals(history.size(), 0);
});
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"), new Date(), "Coucou Arnaud !"), null);
db.addMessage(new Message(new UserInformation(2, "Arnaud"), new UserInformation(1, "Yohan"), new Date(), "Coucou Yohan !"), null);
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"), new Date(), "Ça va ?"), null);
db.addMessage(new Message(new UserInformation(2, "Arnaud"), new UserInformation(1, "Yohan"), new Date(), "Ouais et toi ?"), null);
db.addMessage(new Message(new UserInformation(1, "Yohan"), new UserInformation(2, "Arnaud"), new Date(), "Super !"), null);
db.getAllUsers(users -> {
assertEquals(2, users.size());
assertEquals(1, users.get(0).getId());
assertEquals(2, users.get(1).getId());
assertEquals("Yohan", users.get(0).getUsername());
assertEquals("Arnaud", users.get(1).getUsername());
});
db.getChatHistory(new UserInformation(1, "Yohan"), new Date(0), new Date(), history -> {
assertEquals(5, history.size());
assertEquals("Coucou Arnaud !", history.get(0).getText());
assertEquals(1, history.get(0).getSender().id);
assertEquals(2, history.get(0).getRecipient().id);
assertEquals("Yohan", history.get(0).getSender().getUsername());
assertEquals("Arnaud", history.get(0).getRecipient().getUsername());
assertEquals("Ouais et toi ?", history.get(3).getText());
assertEquals(2, history.get(3).getSender().id);
assertEquals(1, history.get(3).getRecipient().id);
assertEquals("Arnaud", history.get(3).getSender().getUsername());
assertEquals("Yohan", history.get(3).getRecipient().getUsername());
});
db.resetTables();
db.close();
}