make DatabaseController async
This commit is contained in:
parent
6d3971be40
commit
1ab27f4f87
9 changed files with 359 additions and 258 deletions
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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? */);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue