diff --git a/.idea/clavardator.iml b/.idea/clavardator.iml
new file mode 100644
index 0000000..78b2cc5
--- /dev/null
+++ b/.idea/clavardator.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 645f4a0..3198fd2 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -3,18 +3,9 @@
-
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index fb7f4a8..ac216bc 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 1cd02f1..c66ef85 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -9,7 +9,7 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/fr/insa/clavardator/MainApp.java b/src/main/java/fr/insa/clavardator/MainApp.java
index de8e789..fb1807d 100644
--- a/src/main/java/fr/insa/clavardator/MainApp.java
+++ b/src/main/java/fr/insa/clavardator/MainApp.java
@@ -12,6 +12,8 @@ import javafx.stage.Stage;
public class MainApp extends Application {
+ NetDiscoverer netDiscoverer;
+
public static void main(String[] args) {
launch(args);
}
@@ -34,16 +36,18 @@ public class MainApp extends Application {
stage.setMaximized(true);
stage.show();
+ netDiscoverer = new NetDiscoverer();
+
// Network discovery test
- NetDiscoverer.discoverActiveUsers("Broadcast",
+ netDiscoverer.discoverActiveUsers("Broadcast",
(ipAddr, data) -> System.out.println("User detected at address : " + ipAddr.toString()),
Throwable::printStackTrace);
- NetDiscoverer.startDiscoveryListening("Yohan", null, Throwable::printStackTrace);
+ netDiscoverer.startDiscoveryListening("Yohan", null, Throwable::printStackTrace);
}
@Override
public void stop() throws Exception {
- NetDiscoverer.stopDiscovery();
+ netDiscoverer.stopDiscovery();
super.stop();
}
}
\ No newline at end of file
diff --git a/src/main/java/fr/insa/clavardator/chat/Message.java b/src/main/java/fr/insa/clavardator/chat/Message.java
index 54ecaa9..62fce4c 100644
--- a/src/main/java/fr/insa/clavardator/chat/Message.java
+++ b/src/main/java/fr/insa/clavardator/chat/Message.java
@@ -1,14 +1,13 @@
package fr.insa.clavardator.chat;
-import fr.insa.clavardator.users.CurrentUser;
import fr.insa.clavardator.users.User;
import java.io.Serializable;
public class Message implements Serializable {
- private String text;
- private final User recipient;
+ private final String text;
private final User sender;
+ private final User recipient;
public Message(User sender, User recipient) {
this(sender, recipient, "");
@@ -27,4 +26,8 @@ public class Message implements Serializable {
public User getSender() {
return sender;
}
+
+ public User getRecipient() {
+ return recipient;
+ }
}
diff --git a/src/main/java/fr/insa/clavardator/network/ConnectionListener.java b/src/main/java/fr/insa/clavardator/network/ConnectionListener.java
new file mode 100644
index 0000000..81d3d6f
--- /dev/null
+++ b/src/main/java/fr/insa/clavardator/network/ConnectionListener.java
@@ -0,0 +1,67 @@
+package fr.insa.clavardator.network;
+
+import fr.insa.clavardator.users.ActiveUser;
+import fr.insa.clavardator.util.ErrorCallback;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+public class ConnectionListener {
+ Acceptor acceptor = null;
+
+ ConnectionListener() {
+ }
+
+ public void acceptConnection(NewConnectionCallback callback, ErrorCallback errorCallback) {
+ if (acceptor != null) {
+ acceptor.stopAccepting();
+ }
+ acceptor = new Acceptor(callback, errorCallback);
+ }
+
+ public void stopAccepting() {
+ acceptor.stopAccepting();
+ }
+
+
+ private static class Acceptor extends Thread {
+ private boolean shouldStop = false;
+ NewConnectionCallback callback;
+ ErrorCallback errorCallback;
+ ServerSocket server;
+
+ public Acceptor(NewConnectionCallback callback, ErrorCallback errorCallback) {
+ this.callback = callback;
+ this.errorCallback = errorCallback;
+ }
+
+ @Override
+ public void run() {
+ try {
+ server = new ServerSocket(PeerConnection.TCP_PORT);
+ while (!shouldStop) {
+ Socket clientSocket = server.accept();
+ ActiveUser newUser = new ActiveUser(clientSocket);
+ callback.onNewConnection(newUser);
+ }
+ } catch (IOException e) {
+ errorCallback.onError(e);
+ }
+
+ }
+
+ public void stopAccepting() {
+ shouldStop = true;
+ try {
+ server.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
+
+
+ interface NewConnectionCallback {
+ void onNewConnection(ActiveUser user);
+ }
+}
diff --git a/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java b/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java
index c54e89e..22c8a11 100644
--- a/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java
+++ b/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java
@@ -16,11 +16,12 @@ public class NetDiscoverer {
private static final int BROADCAST_BUFFER_SIZE = 50;
private static final int RESPONSE_BUFFER_SIZE = 50;
- private static DatagramSocket broadcastListener;
- private static DatagramSocket responseListener;
- private static boolean shouldStop = false;
+ private BroadcastSender broadcastSender;
+ private BroadcastListener socket;
+ private ResponseSender responseSender;
+ private ResponseListener responseListener;
- private NetDiscoverer() {
+ public NetDiscoverer() {
}
/**
@@ -30,11 +31,13 @@ public class NetDiscoverer {
* @param callback function to call when a new user is discovered
* @param errorCallback function to call on error
*/
- public static void discoverActiveUsers(String broadcastMessage, ResponseReceivedCallback callback, ErrorCallback errorCallback) {
- ResponseListener receiver = new ResponseListener(callback, errorCallback);
- BroadcastSender sender = new BroadcastSender(broadcastMessage, errorCallback);
- receiver.start();
- sender.start();
+ public void discoverActiveUsers(String broadcastMessage, ResponseReceivedCallback callback, ErrorCallback errorCallback) {
+ if (responseListener != null)
+ responseListener.stopListening();
+ responseListener = new ResponseListener(callback, errorCallback);
+ broadcastSender = new BroadcastSender(broadcastMessage, errorCallback);
+ responseListener.start();
+ broadcastSender.start();
}
/**
@@ -44,29 +47,31 @@ public class NetDiscoverer {
* @param onBroadcastReceived The function to call on success
* @param errorCallback The function to call on error
*/
- public static void startDiscoveryListening(String responseMessage, @Nullable BroadcastReceivedCallback onBroadcastReceived, @Nullable ErrorCallback errorCallback) {
- BroadcastListener listener = new BroadcastListener((ipAddr, data) -> {
+ public void startDiscoveryListening(String responseMessage, @Nullable BroadcastReceivedCallback onBroadcastReceived, @Nullable ErrorCallback errorCallback) {
+ if (socket != null)
+ socket.stopListening();
+
+ socket = new BroadcastListener((ipAddr, data) -> {
if (onBroadcastReceived != null)
onBroadcastReceived.onBroadcastReceived(ipAddr, data);
- ResponseSender sender = new ResponseSender(ipAddr, responseMessage, errorCallback);
- sender.start();
+ responseSender = new ResponseSender(ipAddr, responseMessage, errorCallback);
+ responseSender.start();
}, e -> {
if (errorCallback != null)
errorCallback.onError(e);
});
- listener.start();
+ socket.start();
}
/**
* Stop network discovery and listening
*/
- public static void stopDiscovery() {
- shouldStop = true;
- if (broadcastListener != null)
- broadcastListener.close();
+ public void stopDiscovery() {
+ if (socket != null)
+ socket.stopListening();
if (responseListener != null)
- responseListener.close();
+ responseListener.stopListening();
}
@@ -105,6 +110,8 @@ public class NetDiscoverer {
private static class BroadcastListener extends Thread {
private final BroadcastReceivedCallback callback;
private final ErrorCallback errorCallback;
+ private DatagramSocket socket;
+ private boolean shouldStop = false;
/**
* Constructs a thread that sends a broadcast over the network, using all available interfaces
@@ -121,15 +128,15 @@ public class NetDiscoverer {
public void run() {
try {
while (!shouldStop) {
- broadcastListener = new DatagramSocket(null);
- broadcastListener.setOption(StandardSocketOptions.SO_REUSEPORT, true);
- broadcastListener.setOption(StandardSocketOptions.SO_REUSEADDR, true);
- broadcastListener.bind(new InetSocketAddress((InetAddress) null, DISCOVERY_PORT));
+ socket = new DatagramSocket(null);
+ socket.setOption(StandardSocketOptions.SO_REUSEPORT, true);
+ socket.setOption(StandardSocketOptions.SO_REUSEADDR, true);
+ socket.bind(new InetSocketAddress((InetAddress) null, DISCOVERY_PORT));
byte[] buffer = new byte[BROADCAST_BUFFER_SIZE];
DatagramPacket receivedPacket = new DatagramPacket(buffer, BROADCAST_BUFFER_SIZE);
- broadcastListener.receive(receivedPacket);
+ socket.receive(receivedPacket);
// System.out.println("broadcast received from " + receivedPacket.getAddress().toString());
callback.onBroadcastReceived(receivedPacket.getAddress(), new String(receivedPacket.getData()));
}
@@ -139,6 +146,11 @@ public class NetDiscoverer {
}
}
}
+
+ public void stopListening() {
+ shouldStop = true;
+ socket.close();
+ }
}
private static class ResponseSender extends Thread {
@@ -175,6 +187,8 @@ public class NetDiscoverer {
private static class ResponseListener extends Thread {
private final ResponseReceivedCallback callback;
private final ErrorCallback errorCallback;
+ private DatagramSocket socket;
+ private boolean shouldStop = false;
/**
* Constructs a thread that receives all UDP responses, until stopDiscovery() is called
@@ -191,14 +205,14 @@ public class NetDiscoverer {
public void run() {
try {
while (!shouldStop) {
- responseListener = new DatagramSocket(null);
- responseListener.setOption(StandardSocketOptions.SO_REUSEPORT, true);
- responseListener.setOption(StandardSocketOptions.SO_REUSEADDR, true);
- responseListener.bind(new InetSocketAddress((InetAddress) null, RESPONSE_PORT));
+ socket = new DatagramSocket(null);
+ socket.setOption(StandardSocketOptions.SO_REUSEPORT, true);
+ socket.setOption(StandardSocketOptions.SO_REUSEADDR, true);
+ socket.bind(new InetSocketAddress((InetAddress) null, RESPONSE_PORT));
byte[] buffer = new byte[RESPONSE_BUFFER_SIZE];
DatagramPacket receivedPacket = new DatagramPacket(buffer, RESPONSE_BUFFER_SIZE);
- responseListener.receive(receivedPacket);
+ socket.receive(receivedPacket);
// System.out.println("response received from " + receivedPacket.getAddress().toString());
callback.onResponseReceived(receivedPacket.getAddress(), new String(receivedPacket.getData()));
}
@@ -208,6 +222,12 @@ public class NetDiscoverer {
}
}
}
+
+ public void stopListening() {
+ shouldStop = true;
+ socket.close();
+ }
+
}
diff --git a/src/main/java/fr/insa/clavardator/network/PeerConnection.java b/src/main/java/fr/insa/clavardator/network/PeerConnection.java
index ca60fa5..5cc9f75 100644
--- a/src/main/java/fr/insa/clavardator/network/PeerConnection.java
+++ b/src/main/java/fr/insa/clavardator/network/PeerConnection.java
@@ -1,6 +1,5 @@
package fr.insa.clavardator.network;
-import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.util.ErrorCallback;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -13,13 +12,21 @@ import java.net.InetAddress;
import java.net.Socket;
public class PeerConnection {
- public static final short PORT = 31598;
+ public static final short TCP_PORT = 31598;
+ Socket socket;
private final ObjectOutputStream outputStream;
private final ObjectInputStream inputStream;
+ private boolean shouldStop = false;
public PeerConnection(InetAddress ipAddr) throws IOException {
- Socket socket = new Socket(ipAddr, PORT);
+ socket = new Socket(ipAddr, TCP_PORT);
+ outputStream = new ObjectOutputStream(socket.getOutputStream());
+ inputStream = new ObjectInputStream(socket.getInputStream());
+ }
+
+ public PeerConnection(Socket socket) throws IOException {
+ this.socket = socket;
outputStream = new ObjectOutputStream(socket.getOutputStream());
inputStream = new ObjectInputStream(socket.getInputStream());
}
@@ -31,22 +38,30 @@ public class PeerConnection {
* @param callback The function to call on success
* @param errorCallback The function to call on error
*/
- public void sendMessage(Message message, MessageSentCallback callback, ErrorCallback errorCallback) {
+ public void send(Serializable message, MessageSentCallback callback, ErrorCallback errorCallback) {
Sender sender = new Sender(message, callback, errorCallback);
sender.start();
}
/**
- * Receives a message from the peer
+ * Subscibe to all incoming messages from the peer
*
- * @param callback The function to call on success
+ * @param callback The function to call when a message is received
* @param errorCallback The function to call on error
*/
- public void receiveMessage(MessageReceivedCallback callback, ErrorCallback errorCallback) {
+ public void receive(MessageReceivedCallback callback, ErrorCallback errorCallback) {
Receiver receiver = new Receiver(callback, errorCallback);
receiver.start();
}
+ public void close() {
+ shouldStop = true;
+ try {
+ socket.close();
+ } catch (IOException ignored) {
+ }
+ }
+
private class Sender extends Thread {
private final Serializable message;
@@ -73,7 +88,7 @@ public class PeerConnection {
if (callback != null)
callback.onMessageSent();
} catch (IOException e) {
- if (errorCallback != null)
+ if (errorCallback != null && !shouldStop)
errorCallback.onError(e);
}
}
@@ -83,6 +98,7 @@ public class PeerConnection {
private final MessageReceivedCallback callback;
private final ErrorCallback errorCallback;
+
/**
* Constructs a thread that receives a message using the socket of the outer class
*
@@ -97,15 +113,11 @@ public class PeerConnection {
@Override
public void run() {
try {
- Object msg = inputStream.readObject();
- if (msg.getClass().isInstance(Message.class)) {
- callback.onMessageReceived((Message) msg);
- } else {
- if (errorCallback != null)
- errorCallback.onError(new ClassCastException("The message received is not a valid Message object"));
+ while(!shouldStop) {
+ callback.onMessageReceived(inputStream.readObject());
}
} catch (IOException | ClassNotFoundException e) {
- if (errorCallback != null)
+ if (errorCallback != null && !shouldStop)
errorCallback.onError(e);
}
}
@@ -113,7 +125,7 @@ public class PeerConnection {
public interface MessageReceivedCallback {
- void onMessageReceived(Message msg);
+ void onMessageReceived(Object msg);
}
public interface MessageSentCallback {
diff --git a/src/main/java/fr/insa/clavardator/users/ActiveUser.java b/src/main/java/fr/insa/clavardator/users/ActiveUser.java
index d08b28e..4c8a406 100644
--- a/src/main/java/fr/insa/clavardator/users/ActiveUser.java
+++ b/src/main/java/fr/insa/clavardator/users/ActiveUser.java
@@ -2,33 +2,67 @@ package fr.insa.clavardator.users;
import fr.insa.clavardator.chat.Message;
import fr.insa.clavardator.network.PeerConnection;
+import fr.insa.clavardator.util.ErrorCallback;
import java.io.IOException;
import java.net.InetAddress;
+import java.net.Socket;
public class ActiveUser extends PeerUser {
- private transient PeerConnection connection;
+ private final transient PeerConnection connection;
+ /**
+ * Creates an active user and connects to him/her
+ * @param username The username of the new user
+ * @param ipAddr The IP address of the new user
+ * @throws IOException when an error occurs during the connection
+ */
public ActiveUser(String username, InetAddress ipAddr) throws IOException {
super(username);
connection = new PeerConnection(ipAddr);
+ subscibeToMessages();
+ connection.send(new UsernameChange("", "currentUser.username"), null, null); // TODO: get currentUser + error handling
+ }
+
+ public ActiveUser(Socket socket) throws IOException {
+ super("");
+ connection = new PeerConnection(socket);
+ subscibeToMessages();
+ }
+
+ private void subscibeToMessages() {
+ connection.receive(
+ msg -> {
+ if (msg.getClass().isInstance(UsernameChange.class)) {
+ setUsername(((UsernameChange)msg).getNewUsername());
+
+ } else if (msg.getClass().isInstance(Message.class)) {
+ // TODO
+ }
+ },
+ error -> {
+ // TODO
+ });
}
/**
- * @param message
+ * Sends a message to this peer
+ * @param message The message to send
+ * @param callback The function to call when the message is sent
+ * @param errorCallback The function to call on error
*/
- public void sendMessage(Message message) {
-// connection.sendMessage(message);
+ public void sendMessage(Message message, PeerConnection.MessageSentCallback callback, ErrorCallback errorCallback) {
+ connection.send(message, callback, errorCallback);
}
-
/**
- * @param message
+ * Closes the connection with the user.
+ * Must be called before exiting the app.
*/
- public void onMessageSent(Message message) {
+ public void destroy() {
+ connection.close();
}
-
}
diff --git a/src/main/java/fr/insa/clavardator/users/CurrentUser.java b/src/main/java/fr/insa/clavardator/users/CurrentUser.java
index 945c0d5..d3034b6 100644
--- a/src/main/java/fr/insa/clavardator/users/CurrentUser.java
+++ b/src/main/java/fr/insa/clavardator/users/CurrentUser.java
@@ -1,18 +1,7 @@
package fr.insa.clavardator.users;
public class CurrentUser extends User {
-
public CurrentUser(String username, UserList userList) {
super(username);
}
-
- /**
- * @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/User.java b/src/main/java/fr/insa/clavardator/users/User.java
index 81edee6..adc668c 100644
--- a/src/main/java/fr/insa/clavardator/users/User.java
+++ b/src/main/java/fr/insa/clavardator/users/User.java
@@ -22,13 +22,16 @@ public class User implements Serializable, Comparable {
this.username = username;
}
- /**
- * @return the current value of username
- */
+
public String getUsername() {
return username;
}
+ protected void setUsername(String newUsername) {
+ pcs.firePropertyChange("username", this.username, newUsername);
+ this.username = newUsername;
+ }
+
@Override
public int compareTo(@NotNull User o) {
diff --git a/src/main/java/fr/insa/clavardator/users/UserList.java b/src/main/java/fr/insa/clavardator/users/UserList.java
index c46c8d3..b485877 100644
--- a/src/main/java/fr/insa/clavardator/users/UserList.java
+++ b/src/main/java/fr/insa/clavardator/users/UserList.java
@@ -15,6 +15,7 @@ public class UserList {
private ArrayList activeUsers;
private ArrayList inactiveUsers;
private final DatabaseController db = new DatabaseController();
+ private final NetDiscoverer netDiscoverer = new NetDiscoverer();
// Make this class observable
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
@@ -28,6 +29,18 @@ public class UserList {
public UserList() {
}
+ /**
+ * Close all running threads, sockets and db connection
+ * Must be called before exiting the app
+ */
+ public void destroy() {
+ netDiscoverer.stopDiscovery();
+// db.close();
+ for (ActiveUser user : activeUsers) {
+ user.destroy();
+ }
+ }
+
/**
* @param username
* @return boolean
@@ -50,7 +63,7 @@ public class UserList {
*
*/
public void discoverActiveUsers(ErrorCallback errorCallback) {
- NetDiscoverer.discoverActiveUsers("CLAVARDATOR_BROADCAST", (ipAddr, data) -> {
+ netDiscoverer.discoverActiveUsers("CLAVARDATOR_BROADCAST", (ipAddr, data) -> {
ActiveUser newUser = null;
try {
newUser = new ActiveUser("", ipAddr); // TODO find username
diff --git a/src/main/java/fr/insa/clavardator/users/UsernameChange.java b/src/main/java/fr/insa/clavardator/users/UsernameChange.java
new file mode 100644
index 0000000..2985854
--- /dev/null
+++ b/src/main/java/fr/insa/clavardator/users/UsernameChange.java
@@ -0,0 +1,21 @@
+package fr.insa.clavardator.users;
+
+import java.io.Serializable;
+
+public class UsernameChange implements Serializable {
+ private final String prevUsername; // Not sure if this is useful
+ private final String newUsername;
+
+ public UsernameChange(String previousUsername, String newUsername) {
+ this.prevUsername = previousUsername;
+ this.newUsername = newUsername;
+ }
+
+ public String getPreviousUsername() {
+ return prevUsername;
+ }
+
+ public String getNewUsername() {
+ return newUsername;
+ }
+}