From 659bdd10ec8072c94644f14ba21d0b86f2060bae Mon Sep 17 00:00:00 2001 From: Yohan Simard Date: Thu, 26 Nov 2020 16:18:29 +0100 Subject: [PATCH] Convert to beans, start implementing functions and rewrite net architecture --- .../fr/insa/clavardator/FXMLController.java | 9 +- .../fr/insa/clavardator/chat/ChatHistory.java | 72 ++++++++------- .../fr/insa/clavardator/chat/FileMessage.java | 41 +++++++++ .../insa/clavardator/chat/ImageMessage.java | 13 +++ .../fr/insa/clavardator/chat/Message.java | 23 ++++- .../clavardator/db/DatabaseController.java | 43 ++++++--- .../clavardator/network/NetDiscoverer.java | 84 +++++++++++++++++ .../network/NetworkConnection.java | 52 ----------- .../clavardator/network/PeerConnection.java | 89 +++++++++++++++++++ .../fr/insa/clavardator/users/ActiveUser.java | 10 ++- .../insa/clavardator/users/CurrentUser.java | 5 +- .../fr/insa/clavardator/users/PeerUser.java | 3 +- .../java/fr/insa/clavardator/users/User.java | 30 +++---- .../fr/insa/clavardator/users/UserList.java | 63 +++++++------ .../insa/clavardator/util/ErrorHandler.java | 36 ++++---- 15 files changed, 401 insertions(+), 172 deletions(-) create mode 100644 src/main/java/fr/insa/clavardator/chat/FileMessage.java create mode 100644 src/main/java/fr/insa/clavardator/chat/ImageMessage.java create mode 100644 src/main/java/fr/insa/clavardator/network/NetDiscoverer.java delete mode 100644 src/main/java/fr/insa/clavardator/network/NetworkConnection.java create mode 100644 src/main/java/fr/insa/clavardator/network/PeerConnection.java diff --git a/src/main/java/fr/insa/clavardator/FXMLController.java b/src/main/java/fr/insa/clavardator/FXMLController.java index f434146..8090d20 100644 --- a/src/main/java/fr/insa/clavardator/FXMLController.java +++ b/src/main/java/fr/insa/clavardator/FXMLController.java @@ -4,10 +4,12 @@ import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Label; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.net.URL; import java.util.ResourceBundle; -public class FXMLController implements Initializable { +public class FXMLController implements Initializable, PropertyChangeListener { @FXML private Label label; @@ -18,4 +20,9 @@ public class FXMLController implements Initializable { String javafxVersion = System.getProperty("javafx.version"); label.setText("-= CLAVARDATOR =-\nusing JavaFX " + javafxVersion + "\nRunning on Java " + javaVersion + "."); } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + + } } \ No newline at end of file diff --git a/src/main/java/fr/insa/clavardator/chat/ChatHistory.java b/src/main/java/fr/insa/clavardator/chat/ChatHistory.java index 80dd94a..38ff199 100644 --- a/src/main/java/fr/insa/clavardator/chat/ChatHistory.java +++ b/src/main/java/fr/insa/clavardator/chat/ChatHistory.java @@ -1,20 +1,42 @@ package fr.insa.clavardator.chat; import fr.insa.clavardator.db.DatabaseController; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; +import fr.insa.clavardator.users.User; -public class ChatHistory implements Observable { +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.Date; - private DatabaseController db; +public class ChatHistory { + private final DatabaseController db; + private final User user; + private ArrayList history = new ArrayList<>(); - public ChatHistory() { + public ChatHistory(User user) { + this.user = user; + db = new DatabaseController(user); } - /** - * - */ - public void refreshHistory() { + // Make this class observable + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + public void addObserver(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + + public void removeObserver(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } + + + private void getHistory() { + db.getChatHistory(new Date(), new Date(), // TODO: put actual date + newHistory -> { + ArrayList oldHistory = history; + history = newHistory; + pcs.firePropertyChange("history", oldHistory, history); // Does this work? + }); } @@ -22,30 +44,12 @@ public class ChatHistory implements Observable { * @param message */ public void addMessage(Message message) { - } - - - /** - * @param message - */ - public void onMessageSaved(Message message) { - } - - - /** - * - */ - public void onMessagesFetched() { - } - - - @Override - public void addListener(InvalidationListener listener) { - - } - - @Override - public void removeListener(InvalidationListener listener) { - + db.addMessage(message, new DatabaseController.MessageCallback() { + @Override + public void onMessageSaved(Message savedMessage) { + history.add(savedMessage); + pcs.firePropertyChange("history", null, history); + } + }); } } diff --git a/src/main/java/fr/insa/clavardator/chat/FileMessage.java b/src/main/java/fr/insa/clavardator/chat/FileMessage.java new file mode 100644 index 0000000..b741f30 --- /dev/null +++ b/src/main/java/fr/insa/clavardator/chat/FileMessage.java @@ -0,0 +1,41 @@ +package fr.insa.clavardator.chat; + +import fr.insa.clavardator.users.User; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class FileMessage extends Message { + public static final long MAX_FILE_SIZE = 20 * 1024 * 1024; // 20 Mo + + private final byte[] rawFile; + private final String fileName; + + public FileMessage(User sender, User recipient, String filePath, String text) throws IOException { + super(sender, recipient, text); + + File file = new File(filePath); + if (!file.exists()) + throw new IOException("The file does not exist"); + if (!file.canRead()) + throw new IOException("The file is not readable"); + if (!file.isFile()) + throw new IOException("The path does not lead to a file"); + if (file.length() > MAX_FILE_SIZE) + throw new IOException("The file is too large"); + + fileName = file.getName(); + + FileInputStream stream = new FileInputStream(file); + rawFile = stream.readAllBytes(); + } + + public byte[] getRawFile() { + return rawFile; + } + + public String getFileName() { + return fileName; + } +} \ No newline at end of file diff --git a/src/main/java/fr/insa/clavardator/chat/ImageMessage.java b/src/main/java/fr/insa/clavardator/chat/ImageMessage.java new file mode 100644 index 0000000..382bf20 --- /dev/null +++ b/src/main/java/fr/insa/clavardator/chat/ImageMessage.java @@ -0,0 +1,13 @@ +package fr.insa.clavardator.chat; + +import fr.insa.clavardator.users.User; + +public class ImageMessage extends Message { + public ImageMessage(User sender, User recipient) { + super(sender, recipient); + } + + public ImageMessage(User sender, User recipient, String text) { + super(sender, recipient, text); + } +} diff --git a/src/main/java/fr/insa/clavardator/chat/Message.java b/src/main/java/fr/insa/clavardator/chat/Message.java index 530ff68..12d148a 100644 --- a/src/main/java/fr/insa/clavardator/chat/Message.java +++ b/src/main/java/fr/insa/clavardator/chat/Message.java @@ -1,6 +1,25 @@ package fr.insa.clavardator.chat; -public class Message { - public Message() { +import fr.insa.clavardator.users.User; + +import java.io.Serializable; + +public class Message implements Serializable { + private String text; + private final User recipient; + private final User sender; + + public Message(User sender, User recipient) { + this(sender, recipient, ""); + } + + public Message(User sender, User recipient, String text) { + this.sender = sender; + this.recipient = recipient; + this.text = text; + } + + public String getText() { + return text; } } diff --git a/src/main/java/fr/insa/clavardator/db/DatabaseController.java b/src/main/java/fr/insa/clavardator/db/DatabaseController.java index d77346c..48420f6 100644 --- a/src/main/java/fr/insa/clavardator/db/DatabaseController.java +++ b/src/main/java/fr/insa/clavardator/db/DatabaseController.java @@ -1,39 +1,62 @@ package fr.insa.clavardator.db; import fr.insa.clavardator.chat.Message; +import fr.insa.clavardator.users.User; -public class DatabaseController extends Thread { - public DatabaseController() { +import java.util.ArrayList; +import java.util.Date; + +public class DatabaseController { + private final User user; + + public DatabaseController(User user) { + this.user = user; } + public DatabaseController() { + user = null; + } + + /** - * @param callback + * 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) { + } /** - * @param message - * @param callback + * 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 */ public void addMessage(Message message, MessageCallback callback) { + } /** - * @param callback + * Get the chat history for a given time frame + * @param from the starting date + * @param to the ending date + * @param callback Function called when the request is done */ - public void getChatHistory(HistoryCallback callback) { + public void getChatHistory(Date from, Date to, HistoryCallback callback) { + } - private interface UsersCallback { + public interface UsersCallback { + void onUsersFetched(ArrayList users); } - private interface HistoryCallback { + public interface HistoryCallback { + void onHistoryFetched(ArrayList history); } - private interface MessageCallback { + public interface MessageCallback { + void onMessageSaved(Message history); } } diff --git a/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java b/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java new file mode 100644 index 0000000..61468fe --- /dev/null +++ b/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java @@ -0,0 +1,84 @@ +package fr.insa.clavardator.network; + +import fr.insa.clavardator.users.ActiveUser; +import fr.insa.clavardator.util.ErrorHandler; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; + +public class NetDiscoverer { + private static final short DISCOVERY_PORT = 31596; + private static final short RESPONSE_PORT = 31597; + + public NetDiscoverer() {} + + /** + * @param message + * @param callback + */ + public void sendBroadcast(String message, NetDiscoverer.ResponseReceivedCallback callback) { + NetDiscoverer.BroadcastSender sender = new NetDiscoverer.BroadcastSender(message, callback); + } + + + private static class BroadcastSender extends Thread { + String broadcastMessage; + NetDiscoverer.ResponseReceivedCallback callback; + + /** + * Constructs and starts a thread that sends a broadcast over the network + * @param broadcastMessage The message to send + * @param callback The function to call once finished + */ + public BroadcastSender(String broadcastMessage, NetDiscoverer.ResponseReceivedCallback callback) { + this.broadcastMessage = broadcastMessage; + this.callback = callback; + start(); + } + + @Override + public void run() { + byte[] buf = broadcastMessage.getBytes(); + try { + DatagramSocket broadcastSocket = new DatagramSocket(DISCOVERY_PORT); + broadcastSocket.setBroadcast(true); + broadcastSocket.bind(null); + broadcastSocket.send(new DatagramPacket(buf, buf.length)); + + } catch (IOException e) { + ErrorHandler.getInstance().notifyError(e); + } + + } + } + + private static class Listener extends Thread { + final short port; + + + public Listener(short port) { + this.port = port; + } + + @Override + public void run() { + //TODO + } + } + + + public interface ResponseReceivedCallback { + void onActiverUserDiscovered(ActiveUser user); + } + private interface ResponseSentCallback { + void onResponseSent(); + } + private interface BroadcastReceivedCallback { + void onBroadcastReceived(InetAddress ipAddr); + } + private interface BroadcastSentCallback { + void onBroadcastSent(); + } +} diff --git a/src/main/java/fr/insa/clavardator/network/NetworkConnection.java b/src/main/java/fr/insa/clavardator/network/NetworkConnection.java deleted file mode 100644 index e525fe1..0000000 --- a/src/main/java/fr/insa/clavardator/network/NetworkConnection.java +++ /dev/null @@ -1,52 +0,0 @@ -package fr.insa.clavardator.network; - -import fr.insa.clavardator.chat.Message; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; - -import java.net.Socket; - -public class NetworkConnection implements Runnable, Observable { - - private Socket socket; - - public NetworkConnection() { - } - - /** - * @param message - * @param callback - */ - public void sendMessage(Message message, MessageCallback callback) { - } - - - /** - * @param message - * @param callback - */ - public void sendBroadcast(String message, BroadcastCallback callback) { - } - - - @Override - public void run() { - - } - - @Override - public void addListener(InvalidationListener listener) { - - } - - @Override - public void removeListener(InvalidationListener listener) { - - } - - public interface MessageCallback { - } - - public interface BroadcastCallback { - } -} diff --git a/src/main/java/fr/insa/clavardator/network/PeerConnection.java b/src/main/java/fr/insa/clavardator/network/PeerConnection.java new file mode 100644 index 0000000..a75bf8d --- /dev/null +++ b/src/main/java/fr/insa/clavardator/network/PeerConnection.java @@ -0,0 +1,89 @@ +package fr.insa.clavardator.network; + +import fr.insa.clavardator.chat.Message; +import fr.insa.clavardator.util.ErrorHandler; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.InetAddress; +import java.net.Socket; + +public class PeerConnection { + public static final short PORT = 31598; + + private Socket socket; + + public PeerConnection(InetAddress ipAddr) { + try { + socket = new Socket(ipAddr, PORT); + } catch (IOException e) { + ErrorHandler.getInstance().notifyError(e); + } + } + + /** + * @param message + * @param callback + */ + public void sendMessage(Message message, MessageSentCallback callback) { + Sender sender = new Sender(message, callback); + sender.start(); + } + + public void receiveMessage(MessageReceivedCallback callback) { + Receiver receiver = new Receiver(callback); + receiver.start(); + } + + + private class Sender extends Thread { + Serializable message; + MessageSentCallback callback; + + /** + * Constructs and starts a thread that sends a message using the socket of the outer class + * @param messsage The message to send + * @param callback The function to call once finished + */ + public Sender(Serializable messsage, MessageSentCallback callback) { + this.message = messsage; + this.callback = callback; + } + + @Override + synchronized public void run() { + try { + // TODO: store the oos in Peer connection? + ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); + oos.writeObject(message); + } catch (IOException e) { + ErrorHandler.getInstance().notifyError(e); + } + callback.onMessageSent(); + } + } + + private class Receiver extends Thread { + MessageReceivedCallback callback; + + public Receiver(MessageReceivedCallback callback) { + this.callback = callback; + } + + @Override + public void run() { + //TODO +// callback.onMessageReceived(); + } + } + + + public interface MessageReceivedCallback { + void onMessageReceived(Message msg); + } + public interface MessageSentCallback { + void onMessageSent(); + } + +} diff --git a/src/main/java/fr/insa/clavardator/users/ActiveUser.java b/src/main/java/fr/insa/clavardator/users/ActiveUser.java index 6766b4c..1080148 100644 --- a/src/main/java/fr/insa/clavardator/users/ActiveUser.java +++ b/src/main/java/fr/insa/clavardator/users/ActiveUser.java @@ -1,13 +1,17 @@ package fr.insa.clavardator.users; import fr.insa.clavardator.chat.Message; -import fr.insa.clavardator.network.NetworkConnection; +import fr.insa.clavardator.network.PeerConnection; + +import java.net.InetAddress; + public class ActiveUser extends PeerUser { - private NetworkConnection networkController; + private transient PeerConnection connection; - public ActiveUser() { + public ActiveUser(InetAddress ipAddr) { + connection = new PeerConnection(ipAddr); } /** diff --git a/src/main/java/fr/insa/clavardator/users/CurrentUser.java b/src/main/java/fr/insa/clavardator/users/CurrentUser.java index bebc76e..b29c2ac 100644 --- a/src/main/java/fr/insa/clavardator/users/CurrentUser.java +++ b/src/main/java/fr/insa/clavardator/users/CurrentUser.java @@ -1,13 +1,16 @@ package fr.insa.clavardator.users; public class CurrentUser extends User { - public CurrentUser() { + + public CurrentUser(UserList userList) { } /** * @param username */ public void changeUsername(String username) { + pcs.firePropertyChange("username", this.username, username); + this.username = username; } diff --git a/src/main/java/fr/insa/clavardator/users/PeerUser.java b/src/main/java/fr/insa/clavardator/users/PeerUser.java index e713a67..3229dae 100644 --- a/src/main/java/fr/insa/clavardator/users/PeerUser.java +++ b/src/main/java/fr/insa/clavardator/users/PeerUser.java @@ -4,9 +4,10 @@ import fr.insa.clavardator.chat.ChatHistory; public class PeerUser extends User { - protected ChatHistory history; + protected transient ChatHistory history; public PeerUser() { + history = new ChatHistory(this); } /** diff --git a/src/main/java/fr/insa/clavardator/users/User.java b/src/main/java/fr/insa/clavardator/users/User.java index 6c2ce33..dcf4975 100644 --- a/src/main/java/fr/insa/clavardator/users/User.java +++ b/src/main/java/fr/insa/clavardator/users/User.java @@ -1,33 +1,29 @@ package fr.insa.clavardator.users; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; - -public class User implements Observable { +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.Serializable; +public class User implements Serializable { protected String username; - public User() { + // Make this class observable + protected final transient PropertyChangeSupport pcs = new PropertyChangeSupport(this); + public void addObserver(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + public void removeObserver(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); } + public User() {} /** - * Get the value of username - * - * @return the value of username + * @return the current value of username */ public String getUsername() { return username; } - @Override - public void addListener(InvalidationListener listener) { - - } - - @Override - public void removeListener(InvalidationListener listener) { - - } } diff --git a/src/main/java/fr/insa/clavardator/users/UserList.java b/src/main/java/fr/insa/clavardator/users/UserList.java index a7d35d8..d5835d9 100644 --- a/src/main/java/fr/insa/clavardator/users/UserList.java +++ b/src/main/java/fr/insa/clavardator/users/UserList.java @@ -1,16 +1,28 @@ package fr.insa.clavardator.users; import fr.insa.clavardator.db.DatabaseController; -import fr.insa.clavardator.network.NetworkConnection; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; +import fr.insa.clavardator.network.NetDiscoverer; -public class UserList implements Observable { +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.ArrayList; +import java.util.function.Predicate; - public ActiveUser activeUsers; - private PeerUser inactiveUsers; - private NetworkConnection network; - private DatabaseController db; +public class UserList { + + private ArrayList activeUsers; + private ArrayList inactiveUsers; + private final NetDiscoverer netDiscoverer = new NetDiscoverer(); + private final DatabaseController db = new DatabaseController(); + + // Make this class observable + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + public void addObserver(PropertyChangeListener listener) { + pcs.addPropertyChangeListener(listener); + } + public void removeObserver(PropertyChangeListener listener) { + pcs.removePropertyChangeListener(listener); + } public UserList() { } @@ -20,7 +32,9 @@ public class UserList implements Observable { * @return boolean */ public boolean isUsernameAvailable(String username) { - return false; + Predicate usernameEqual = user -> user.username.equals(username); + return activeUsers.stream().noneMatch(usernameEqual) && + inactiveUsers.stream().noneMatch(usernameEqual); } @@ -31,34 +45,17 @@ public class UserList implements Observable { } - /** - * - */ - public void onUsernameChangePropagated() { - } - - /** * */ public void discoverActiveUsers() { + netDiscoverer.sendBroadcast("", new NetDiscoverer.ResponseReceivedCallback() { + @Override + public void onActiverUserDiscovered(ActiveUser user) { + activeUsers.add(user); + pcs.firePropertyChange("activeUsers", null, user); + } + }); } - - /** - * @param user - */ - public void onActiverUserDiscovered(ActiveUser user) { - } - - - @Override - public void addListener(InvalidationListener listener) { - - } - - @Override - public void removeListener(InvalidationListener listener) { - - } } diff --git a/src/main/java/fr/insa/clavardator/util/ErrorHandler.java b/src/main/java/fr/insa/clavardator/util/ErrorHandler.java index 4d8adec..5c762b0 100644 --- a/src/main/java/fr/insa/clavardator/util/ErrorHandler.java +++ b/src/main/java/fr/insa/clavardator/util/ErrorHandler.java @@ -1,26 +1,26 @@ package fr.insa.clavardator.util; -import javafx.beans.InvalidationListener; -import javafx.beans.Observable; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; -public class ErrorHandler implements Observable { - public ErrorHandler() { +public class ErrorHandler { + private ErrorHandler() {} + + // Make this class observable + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + public void addObserver(PropertyChangeListener listener) { pcs.addPropertyChangeListener(listener); } + public void removeObserver(PropertyChangeListener listener) { pcs.removePropertyChangeListener(listener); } + + private static ErrorHandler instance; + + public static ErrorHandler getInstance() { + if (instance == null) + instance = new ErrorHandler(); + return instance; } - /** - * @param exception - */ + public void notifyError(Exception exception) { - } - - - @Override - public void addListener(InvalidationListener listener) { - - } - - @Override - public void removeListener(InvalidationListener listener) { - + pcs.firePropertyChange("exception", null, exception); } }