Convert to beans, start implementing functions and rewrite net architecture

This commit is contained in:
Yohan Simard 2020-11-26 16:18:29 +01:00
parent 062880407b
commit 659bdd10ec
15 changed files with 401 additions and 172 deletions

View file

@ -4,10 +4,12 @@ import javafx.fxml.FXML;
import javafx.fxml.Initializable; import javafx.fxml.Initializable;
import javafx.scene.control.Label; import javafx.scene.control.Label;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URL; import java.net.URL;
import java.util.ResourceBundle; import java.util.ResourceBundle;
public class FXMLController implements Initializable { public class FXMLController implements Initializable, PropertyChangeListener {
@FXML @FXML
private Label label; private Label label;
@ -18,4 +20,9 @@ public class FXMLController implements Initializable {
String javafxVersion = System.getProperty("javafx.version"); String javafxVersion = System.getProperty("javafx.version");
label.setText("-= CLAVARDATOR =-\nusing JavaFX " + javafxVersion + "\nRunning on Java " + javaVersion + "."); label.setText("-= CLAVARDATOR =-\nusing JavaFX " + javafxVersion + "\nRunning on Java " + javaVersion + ".");
} }
@Override
public void propertyChange(PropertyChangeEvent evt) {
}
} }

View file

@ -1,20 +1,42 @@
package fr.insa.clavardator.chat; package fr.insa.clavardator.chat;
import fr.insa.clavardator.db.DatabaseController; import fr.insa.clavardator.db.DatabaseController;
import javafx.beans.InvalidationListener; import fr.insa.clavardator.users.User;
import javafx.beans.Observable;
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<Message> history = new ArrayList<>();
public ChatHistory() { public ChatHistory(User user) {
this.user = user;
db = new DatabaseController(user);
} }
/** // Make this class observable
* private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
*/
public void refreshHistory() { 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<Message> oldHistory = history;
history = newHistory;
pcs.firePropertyChange("history", oldHistory, history); // Does this work?
});
} }
@ -22,30 +44,12 @@ public class ChatHistory implements Observable {
* @param message * @param message
*/ */
public void addMessage(Message message) { public void addMessage(Message message) {
} db.addMessage(message, new DatabaseController.MessageCallback() {
@Override
public void onMessageSaved(Message savedMessage) {
/** history.add(savedMessage);
* @param message pcs.firePropertyChange("history", null, history);
*/ }
public void onMessageSaved(Message message) { });
}
/**
*
*/
public void onMessagesFetched() {
}
@Override
public void addListener(InvalidationListener listener) {
}
@Override
public void removeListener(InvalidationListener listener) {
} }
} }

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -1,6 +1,25 @@
package fr.insa.clavardator.chat; package fr.insa.clavardator.chat;
public class Message { import fr.insa.clavardator.users.User;
public Message() {
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;
} }
} }

View file

@ -1,39 +1,62 @@
package fr.insa.clavardator.db; package fr.insa.clavardator.db;
import fr.insa.clavardator.chat.Message; import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.users.User;
public class DatabaseController extends Thread { import java.util.ArrayList;
public DatabaseController() { 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) { public void getAllUsers(UsersCallback callback) {
} }
/** /**
* @param message * Adds a message to the database for this user
* @param callback * @param message The message to add to the database
* @param callback Function called when the request is done
*/ */
public void addMessage(Message message, MessageCallback callback) { public void addMessage(Message message, 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<User> users);
} }
private interface HistoryCallback { public interface HistoryCallback {
void onHistoryFetched(ArrayList<Message> history);
} }
private interface MessageCallback { public interface MessageCallback {
void onMessageSaved(Message history);
} }
} }

View file

@ -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();
}
}

View file

@ -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 {
}
}

View file

@ -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();
}
}

View file

@ -1,13 +1,17 @@
package fr.insa.clavardator.users; package fr.insa.clavardator.users;
import fr.insa.clavardator.chat.Message; 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 { public class ActiveUser extends PeerUser {
private NetworkConnection networkController; private transient PeerConnection connection;
public ActiveUser() { public ActiveUser(InetAddress ipAddr) {
connection = new PeerConnection(ipAddr);
} }
/** /**

View file

@ -1,13 +1,16 @@
package fr.insa.clavardator.users; package fr.insa.clavardator.users;
public class CurrentUser extends User { public class CurrentUser extends User {
public CurrentUser() {
public CurrentUser(UserList userList) {
} }
/** /**
* @param username * @param username
*/ */
public void changeUsername(String username) { public void changeUsername(String username) {
pcs.firePropertyChange("username", this.username, username);
this.username = username;
} }

View file

@ -4,9 +4,10 @@ import fr.insa.clavardator.chat.ChatHistory;
public class PeerUser extends User { public class PeerUser extends User {
protected ChatHistory history; protected transient ChatHistory history;
public PeerUser() { public PeerUser() {
history = new ChatHistory(this);
} }
/** /**

View file

@ -1,33 +1,29 @@
package fr.insa.clavardator.users; package fr.insa.clavardator.users;
import javafx.beans.InvalidationListener; import java.beans.PropertyChangeListener;
import javafx.beans.Observable; import java.beans.PropertyChangeSupport;
import java.io.Serializable;
public class User implements Observable {
public class User implements Serializable {
protected String username; 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 current value of username
*
* @return the value of username
*/ */
public String getUsername() { public String getUsername() {
return username; return username;
} }
@Override
public void addListener(InvalidationListener listener) {
}
@Override
public void removeListener(InvalidationListener listener) {
}
} }

View file

@ -1,16 +1,28 @@
package fr.insa.clavardator.users; package fr.insa.clavardator.users;
import fr.insa.clavardator.db.DatabaseController; import fr.insa.clavardator.db.DatabaseController;
import fr.insa.clavardator.network.NetworkConnection; import fr.insa.clavardator.network.NetDiscoverer;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
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; public class UserList {
private PeerUser inactiveUsers;
private NetworkConnection network; private ArrayList<ActiveUser> activeUsers;
private DatabaseController db; private ArrayList<PeerUser> 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() { public UserList() {
} }
@ -20,7 +32,9 @@ public class UserList implements Observable {
* @return boolean * @return boolean
*/ */
public boolean isUsernameAvailable(String username) { public boolean isUsernameAvailable(String username) {
return false; Predicate<User> 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() { 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) {
}
} }

View file

@ -1,26 +1,26 @@
package fr.insa.clavardator.util; package fr.insa.clavardator.util;
import javafx.beans.InvalidationListener; import java.beans.PropertyChangeListener;
import javafx.beans.Observable; import java.beans.PropertyChangeSupport;
public class ErrorHandler implements Observable { public class ErrorHandler {
public 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) { public void notifyError(Exception exception) {
} pcs.firePropertyChange("exception", null, exception);
@Override
public void addListener(InvalidationListener listener) {
}
@Override
public void removeListener(InvalidationListener listener) {
} }
} }