Implement and test DatabaseController functions

This commit is contained in:
Yohan Simard 2020-12-18 15:06:11 +01:00
parent aed165108c
commit 34255a98e8
10 changed files with 298 additions and 20 deletions

3
.gitignore vendored
View file

@ -2,6 +2,9 @@
**/build/
!src/**/build/
# Ignore sqlite db files
/*.db
# Ignore Gradle GUI config
gradle-app.setting

View file

@ -3,10 +3,12 @@ package fr.insa.clavardator.chat;
import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.PeerUser;
import fr.insa.clavardator.util.Log;
import javafx.application.Platform;
import java.util.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class ChatHistory {
private final DatabaseController db;
@ -17,7 +19,7 @@ public class ChatHistory {
public ChatHistory(PeerUser user) {
this.user = user;
db = new DatabaseController(user);
db = new DatabaseController();
this.historyListener = new ArrayList<>();
this.messageListener = new ArrayList<>();
}

View file

@ -1,6 +1,6 @@
package fr.insa.clavardator.chat;
import fr.insa.clavardator.users.User;
import fr.insa.clavardator.users.UserInformation;
import java.io.File;
import java.io.FileInputStream;
@ -13,7 +13,7 @@ public class FileMessage extends Message {
private final byte[] rawFile;
private final String fileName;
public FileMessage(User sender, User recipient, String filePath, Date date, String text) throws IOException {
public FileMessage(UserInformation sender, UserInformation recipient, Date date, String text, String filePath) throws IOException {
super(sender, recipient, date, text);
File file = new File(filePath);

View file

@ -49,4 +49,14 @@ public class Message implements Serializable {
public Date getDate() {
return date;
}
@Override
public String toString() {
return "Message{" +
"text='" + text + '\'' +
", date=" + date +
", sender=" + sender +
", recipient=" + recipient +
'}';
}
}

View file

@ -1,50 +1,243 @@
package fr.insa.clavardator.db;
import fr.insa.clavardator.chat.FileMessage;
import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.users.User;
import fr.insa.clavardator.users.UserInformation;
import fr.insa.clavardator.util.Log;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
public class DatabaseController {
private final User user;
public DatabaseController(User user) {
this.user = user;
}
private Connection connection;
public DatabaseController() {
user = null;
}
public void connect() {
try {
Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite:clavardator.db");
Log.v(getClass().getSimpleName(), "Opened database successfully");
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
public void close() {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public void initTables() {
try {
Statement stmtMessageTable = connection.createStatement();
String messageTableSql =
"CREATE TABLE IF NOT EXISTS message " +
"(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
" timestamp DATETIME NOT NULL, " +
" sender INTEGER NOT NULL, " +
" recipient INTEGER NOT NULL, " +
" text TEXT, " +
" file_path TEXT)";
Log.v(getClass().getSimpleName(), "Creating table message...");
int rowsModified = stmtMessageTable.executeUpdate(messageTableSql);
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
stmtMessageTable.close();
Statement stmtUserTable = connection.createStatement();
String userTableSql =
"CREATE TABLE IF NOT EXISTS user " +
"(id INTEGER PRIMARY KEY NOT NULL," +
" username INTEGER NOT NULL)";
Log.v(getClass().getSimpleName(), "Creating table user...");
rowsModified = stmtUserTable.executeUpdate(userTableSql);
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
stmtUserTable.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
public void resetTables() {
try {
Statement dropMessage = connection.createStatement();
String dropMessageSql = "DROP TABLE message";
Log.v(getClass().getSimpleName(), "Dropping table message...");
int rowsModified = dropMessage.executeUpdate(dropMessageSql);
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
dropMessage.close();
Statement dropUser = connection.createStatement();
String dropUserSql = "DROP TABLE user";
Log.v(getClass().getSimpleName(), "Dropping table user...");
rowsModified = dropUser.executeUpdate(dropUserSql);
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
dropUser.close();
initTables();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* Fetches the list of users for which we already have a chat history
*
* @param callback Function called when the request is done
*/
public void getAllUsers(UsersCallback callback) {
try {
Statement stmt = connection.createStatement();
String sql = "SELECT * FROM user";
Log.v(getClass().getSimpleName(), "Fetching users from db... ");
ResultSet res = stmt.executeQuery(sql);
Log.v(getClass().getSimpleName(), res.getFetchSize() + " rows fetched");
ArrayList<User> userList = new ArrayList<>();
while (res.next()) {
int id = res.getInt("id");
String username = res.getString("username");
userList.add(new User(id, username));
}
res.close();
stmt.close();
if (callback != null) {
callback.onUsersFetched(userList);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* Adds a message to the database for this user
* @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
*/
public void addMessage(Message message, MessageCallback callback) {
callback.onMessageSaved();
try {
// Insert the new message
final String insertMessageSql =
"INSERT INTO message " +
"(timestamp, sender, recipient, text, file_path) " +
"VALUES (?, ?, ?, ?, ?)";
PreparedStatement insertMsgStmt = connection.prepareStatement(insertMessageSql);
insertMsgStmt.setTimestamp(1, new Timestamp(message.getDate().getTime()));
insertMsgStmt.setInt(2, message.getSender().id);
insertMsgStmt.setInt(3, message.getRecipient().id);
insertMsgStmt.setString(4, message.getText());
if (insertMsgStmt instanceof FileMessage) {
// TODO: store file in file system
Log.w(getClass().getSimpleName(), "Functionality not implemented: file has not been saved");
// stmt.setString(5, ((FileMessage) stmt).getFileName());
} else {
insertMsgStmt.setString(5, null);
}
Log.v(getClass().getSimpleName(), "Inserting message into db... ");
int rowsModified = insertMsgStmt.executeUpdate();
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
insertMsgStmt.close();
// Insert the user if not already existing
final String insertUserSql =
"INSERT OR IGNORE INTO user" +
"(id, username)" +
"VALUES (?, ?)";
PreparedStatement insertUserStmt = connection.prepareStatement(insertUserSql);
// Add sender
insertUserStmt.setInt(1, message.getSender().id);
insertUserStmt.setString(2, message.getSender().getUsername());
Log.v(getClass().getSimpleName(), "Inserting sender into db... ");
rowsModified = insertUserStmt.executeUpdate();
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
// Add recipient
insertUserStmt.setInt(1, message.getRecipient().id);
insertUserStmt.setString(2, message.getRecipient().getUsername());
Log.v(getClass().getSimpleName(), "Inserting recipient into db");
rowsModified = insertUserStmt.executeUpdate();
Log.v(getClass().getSimpleName(), rowsModified + " rows modified");
insertUserStmt.close();
if (callback != null) {
callback.onMessageSaved();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
/**
* Get the chat history for a given time frame
* @param from the starting date
* @param to the ending date
*
* @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
*/
public void getChatHistory(Date from, Date to, HistoryCallback callback) {
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);
Log.v(getClass().getSimpleName(), res.getFetchSize() + " rows fetched");
ArrayList<Message> chatHistory = new ArrayList<>();
while (res.next()) {
int sId = res.getInt("sender_id");
String sUsername = res.getString("sender_username");
int rId = res.getInt("recipient_id");
String rUsername = res.getString("recipient_username");
Date date = new Date(res.getTimestamp("timestamp").getTime());
String text = res.getString("text");
String filePath = res.getString("file_path");
if (filePath == null) {
chatHistory.add(new Message(new UserInformation(sId, sUsername), new UserInformation(rId, rUsername), date, text));
} else {
// TODO
// chatHistory.add(new FileMessage(new UserInformation(sId, sUsername), new UserInformation(rId, rUsername), date, text, filePath));
}
}
res.close();
stmt.close();
if (callback != null) {
callback.onHistoryFetched(chatHistory);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}

View file

@ -44,4 +44,9 @@ public class User implements Serializable {
pcs.firePropertyChange("username", this.username, newUsername);
this.username = newUsername;
}
@Override
public String toString() {
return "User " + id + '(' + username + ')';
}
}

View file

@ -18,4 +18,9 @@ public class UserInformation implements Serializable {
public String getUsername() {
return username;
}
@Override
public String toString() {
return "UserInfo " + id + '(' + username + ')';
}
}

View file

@ -116,9 +116,9 @@ public class UserList {
// Disconnection
if (!activeUsers.containsKey(id)) {
if (inactiveUsers.containsKey(id)) {
Log.e(getClass().getSimpleName(), "Tried to set state DISCONNECTED on an already disconnected user: user id " + id);
Log.w(getClass().getSimpleName(), "Tried to set state DISCONNECTED on an already disconnected user: user id " + id);
} else {
Log.e(getClass().getSimpleName(), "Tried to set state DISCONNECTED on an unknown user: user id " + id);
Log.w(getClass().getSimpleName(), "Tried to set state DISCONNECTED on an unknown user: user id " + id);
}
return;
}

View file

@ -13,7 +13,7 @@ public class Log {
* 3: errors & warnings & debug,
* 4: all
*/
public static int verboseLevel = 0;
public static int verboseLevel = 4;
private static void print(String prefix, String message, String mode, int requiredLevel, @Nullable Exception e) {
if (verboseLevel >= requiredLevel) {

View file

@ -0,0 +1,60 @@
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.Test;
import java.util.Date;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class DatabaseTest {
private final DatabaseController db = new DatabaseController();
@Test
void testDB() {
db.connect();
db.resetTables();
db.getAllUsers(users -> {
assertEquals(0, users.size());
});
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();
}
}