diff --git a/src/main/java/fr/insa/clavardator/MainApp.java b/src/main/java/fr/insa/clavardator/MainApp.java index 8181676..de8e789 100644 --- a/src/main/java/fr/insa/clavardator/MainApp.java +++ b/src/main/java/fr/insa/clavardator/MainApp.java @@ -2,7 +2,6 @@ package fr.insa.clavardator; import fr.insa.clavardator.network.NetDiscoverer; import fr.insa.clavardator.ui.MainController; -import fr.insa.clavardator.util.ErrorHandler; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; @@ -36,12 +35,10 @@ public class MainApp extends Application { stage.show(); // Network discovery test - ErrorHandler.getInstance().addObserver(evt -> ((Exception)evt.getNewValue()).printStackTrace()); - NetDiscoverer.discoverActiveUsers("Broadcast", - (ipAddr, data) -> System.out.println("User detected at address : " + ipAddr.toString()) - ); - NetDiscoverer.startDiscoveryListening("Yohan", null); + (ipAddr, data) -> System.out.println("User detected at address : " + ipAddr.toString()), + Throwable::printStackTrace); + NetDiscoverer.startDiscoveryListening("Yohan", null, Throwable::printStackTrace); } @Override diff --git a/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java b/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java index 57d9ec5..c54e89e 100644 --- a/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java +++ b/src/main/java/fr/insa/clavardator/network/NetDiscoverer.java @@ -1,6 +1,6 @@ package fr.insa.clavardator.network; -import fr.insa.clavardator.util.ErrorHandler; +import fr.insa.clavardator.util.ErrorCallback; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -26,28 +26,41 @@ public class NetDiscoverer { /** * Discovers all active users in the network, and call the callback for each of them * - * @param callback function to call when a new user is discovered + * @param broadcastMessage The message to send as broadcast + * @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) { - ResponseListener receiver = new ResponseListener(callback); - BroadcastSender sender = new BroadcastSender(broadcastMessage); + 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(); } /** * Starts to listen for discovery broadcasts and answers them + * + * @param responseMessage The message to send in response to broadcasts + * @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) { + public static void startDiscoveryListening(String responseMessage, @Nullable BroadcastReceivedCallback onBroadcastReceived, @Nullable ErrorCallback errorCallback) { BroadcastListener listener = new BroadcastListener((ipAddr, data) -> { if (onBroadcastReceived != null) onBroadcastReceived.onBroadcastReceived(ipAddr, data); - new ResponseSender(ipAddr, responseMessage).start(); - } - ); + ResponseSender sender = new ResponseSender(ipAddr, responseMessage, errorCallback); + sender.start(); + }, e -> { + if (errorCallback != null) + errorCallback.onError(e); + }); + listener.start(); } + /** + * Stop network discovery and listening + */ public static void stopDiscovery() { shouldStop = true; if (broadcastListener != null) @@ -58,15 +71,18 @@ public class NetDiscoverer { private static class BroadcastSender extends Thread { - String broadcastMessage; + private final String broadcastMessage; + private final ErrorCallback errorCallback; /** - * Constructs and starts a thread that sends a broadcast over the network + * Constructs a thread that sends a broadcast over the network * * @param broadcastMessage The message to send + * @param errorCallback The function to call on error */ - public BroadcastSender(String broadcastMessage) { + public BroadcastSender(String broadcastMessage, ErrorCallback errorCallback) { this.broadcastMessage = broadcastMessage; + this.errorCallback = errorCallback; } @Override @@ -81,22 +97,30 @@ public class NetDiscoverer { } } catch (IOException e) { - ErrorHandler.getInstance().notifyError(e); + errorCallback.onError(e); } } } private static class BroadcastListener extends Thread { - BroadcastReceivedCallback callback; + private final BroadcastReceivedCallback callback; + private final ErrorCallback errorCallback; - public BroadcastListener(BroadcastReceivedCallback callback) { + /** + * Constructs a thread that sends a broadcast over the network, using all available interfaces + * + * @param callback The function to call on success + * @param errorCallback The function to call on error + */ + public BroadcastListener(BroadcastReceivedCallback callback, ErrorCallback errorCallback) { this.callback = callback; + this.errorCallback = errorCallback; } @Override public void run() { - while (!shouldStop) { - try { + try { + while (!shouldStop) { broadcastListener = new DatagramSocket(null); broadcastListener.setOption(StandardSocketOptions.SO_REUSEPORT, true); broadcastListener.setOption(StandardSocketOptions.SO_REUSEADDR, true); @@ -108,27 +132,31 @@ public class NetDiscoverer { broadcastListener.receive(receivedPacket); // System.out.println("broadcast received from " + receivedPacket.getAddress().toString()); callback.onBroadcastReceived(receivedPacket.getAddress(), new String(receivedPacket.getData())); - } catch (IOException e) { - if (!shouldStop) { - ErrorHandler.getInstance().notifyError(e); - } + } + } catch (IOException e) { + if (!shouldStop) { + errorCallback.onError(e); } } } } private static class ResponseSender extends Thread { - String message; - InetAddress address; + private final String message; + private final InetAddress address; + private final ErrorCallback errorCallback; /** - * Constructs and starts a thread that sends a broadcast over the network + * Constructs a thread that sends a UDP response * - * @param message The message to send + * @param address The address of the remote host + * @param message The message to send + * @param errorCallback The function to call on error */ - public ResponseSender(InetAddress address, String message) { + public ResponseSender(InetAddress address, String message, ErrorCallback errorCallback) { this.address = address; this.message = message; + this.errorCallback = errorCallback; } @Override @@ -139,22 +167,30 @@ public class NetDiscoverer { responseSocket.send(new DatagramPacket(buf, buf.length, address, RESPONSE_PORT)); // System.out.println("Response sent to " + address.toString()); } catch (IOException e) { - ErrorHandler.getInstance().notifyError(e); + errorCallback.onError(e); } } } private static class ResponseListener extends Thread { - ResponseReceivedCallback callback; + private final ResponseReceivedCallback callback; + private final ErrorCallback errorCallback; - public ResponseListener(ResponseReceivedCallback callback) { + /** + * Constructs a thread that receives all UDP responses, until stopDiscovery() is called + * + * @param callback The function to call on success + * @param errorCallback The function to call on error + */ + public ResponseListener(ResponseReceivedCallback callback, ErrorCallback errorCallback) { this.callback = callback; + this.errorCallback = errorCallback; } @Override public void run() { - while (!shouldStop) { - try { + try { + while (!shouldStop) { responseListener = new DatagramSocket(null); responseListener.setOption(StandardSocketOptions.SO_REUSEPORT, true); responseListener.setOption(StandardSocketOptions.SO_REUSEADDR, true); @@ -165,10 +201,10 @@ public class NetDiscoverer { responseListener.receive(receivedPacket); // System.out.println("response received from " + receivedPacket.getAddress().toString()); callback.onResponseReceived(receivedPacket.getAddress(), new String(receivedPacket.getData())); - } catch (IOException e) { - if (!shouldStop) { - ErrorHandler.getInstance().notifyError(e); - } + } + } catch (IOException e) { + if (!shouldStop) { + errorCallback.onError(e); } } } @@ -177,7 +213,7 @@ public class NetDiscoverer { static List listAllBroadcastAddresses() throws SocketException { List broadcastList = new ArrayList<>(); - Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + final Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { NetworkInterface networkInterface = interfaces.nextElement(); @@ -192,12 +228,11 @@ public class NetDiscoverer { } - public interface ResponseReceivedCallback { - void onResponseReceived(InetAddress ipAddr, String data); - } - private interface BroadcastReceivedCallback { void onBroadcastReceived(InetAddress ipAddr, String data); } + public interface ResponseReceivedCallback { + void onResponseReceived(InetAddress ipAddr, String data); + } } diff --git a/src/main/java/fr/insa/clavardator/network/PeerConnection.java b/src/main/java/fr/insa/clavardator/network/PeerConnection.java index a75bf8d..ca60fa5 100644 --- a/src/main/java/fr/insa/clavardator/network/PeerConnection.java +++ b/src/main/java/fr/insa/clavardator/network/PeerConnection.java @@ -1,9 +1,12 @@ package fr.insa.clavardator.network; import fr.insa.clavardator.chat.Message; -import fr.insa.clavardator.util.ErrorHandler; +import fr.insa.clavardator.util.ErrorCallback; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.net.InetAddress; @@ -12,76 +15,107 @@ import java.net.Socket; public class PeerConnection { public static final short PORT = 31598; - private Socket socket; + private final ObjectOutputStream outputStream; + private final ObjectInputStream inputStream; - public PeerConnection(InetAddress ipAddr) { - try { - socket = new Socket(ipAddr, PORT); - } catch (IOException e) { - ErrorHandler.getInstance().notifyError(e); - } + public PeerConnection(InetAddress ipAddr) throws IOException { + Socket socket = new Socket(ipAddr, PORT); + outputStream = new ObjectOutputStream(socket.getOutputStream()); + inputStream = new ObjectInputStream(socket.getInputStream()); } /** - * @param message - * @param callback + * Sends a message to the peer + * + * @param message The message to send + * @param callback The function to call on success + * @param errorCallback The function to call on error */ - public void sendMessage(Message message, MessageSentCallback callback) { - Sender sender = new Sender(message, callback); + public void sendMessage(Message message, MessageSentCallback callback, ErrorCallback errorCallback) { + Sender sender = new Sender(message, callback, errorCallback); sender.start(); } - public void receiveMessage(MessageReceivedCallback callback) { - Receiver receiver = new Receiver(callback); + /** + * Receives a message from the peer + * + * @param callback The function to call on success + * @param errorCallback The function to call on error + */ + public void receiveMessage(MessageReceivedCallback callback, ErrorCallback errorCallback) { + Receiver receiver = new Receiver(callback, errorCallback); receiver.start(); } private class Sender extends Thread { - Serializable message; - MessageSentCallback callback; + private final Serializable message; + private final MessageSentCallback callback; + private final ErrorCallback errorCallback; /** - * 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 + * Constructs 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 on success + * @param errorCallback The function to call on error */ - public Sender(Serializable messsage, MessageSentCallback callback) { + public Sender(Serializable messsage, @Nullable MessageSentCallback callback, @Nullable ErrorCallback errorCallback) { this.message = messsage; this.callback = callback; + this.errorCallback = errorCallback; } @Override synchronized public void run() { try { - // TODO: store the oos in Peer connection? - ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream()); - oos.writeObject(message); + outputStream.writeObject(message); + if (callback != null) + callback.onMessageSent(); } catch (IOException e) { - ErrorHandler.getInstance().notifyError(e); + if (errorCallback != null) + errorCallback.onError(e); } - callback.onMessageSent(); } } private class Receiver extends Thread { - MessageReceivedCallback callback; + private final MessageReceivedCallback callback; + private final ErrorCallback errorCallback; - public Receiver(MessageReceivedCallback callback) { + /** + * Constructs a thread that receives a message using the socket of the outer class + * + * @param callback The function to call on success + * @param errorCallback The function to call on error + */ + public Receiver(@NotNull MessageReceivedCallback callback, @Nullable ErrorCallback errorCallback) { this.callback = callback; + this.errorCallback = errorCallback; } @Override public void run() { - //TODO -// callback.onMessageReceived(); + 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")); + } + } catch (IOException | ClassNotFoundException e) { + if (errorCallback != null) + errorCallback.onError(e); + } } } - public interface MessageReceivedCallback { + public interface MessageReceivedCallback { void onMessageReceived(Message msg); } + public interface MessageSentCallback { void onMessageSent(); } diff --git a/src/main/java/fr/insa/clavardator/ui/users/UserListController.java b/src/main/java/fr/insa/clavardator/ui/users/UserListController.java index 5693462..4dcf503 100644 --- a/src/main/java/fr/insa/clavardator/ui/users/UserListController.java +++ b/src/main/java/fr/insa/clavardator/ui/users/UserListController.java @@ -11,9 +11,9 @@ import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.ListView; +import java.io.IOException; import java.net.InetAddress; import java.net.URL; -import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.ResourceBundle; @@ -65,7 +65,7 @@ public class UserListController implements Initializable { new PeerUser("Dodo1"), new ActiveUser("Coucou2", InetAddress.getLocalHost()) ); - } catch (UnknownHostException e) { + } catch (IOException e) { e.printStackTrace(); } if (activeList != null) { diff --git a/src/main/java/fr/insa/clavardator/users/ActiveUser.java b/src/main/java/fr/insa/clavardator/users/ActiveUser.java index f8c42bb..d08b28e 100644 --- a/src/main/java/fr/insa/clavardator/users/ActiveUser.java +++ b/src/main/java/fr/insa/clavardator/users/ActiveUser.java @@ -3,6 +3,7 @@ package fr.insa.clavardator.users; import fr.insa.clavardator.chat.Message; import fr.insa.clavardator.network.PeerConnection; +import java.io.IOException; import java.net.InetAddress; @@ -10,7 +11,7 @@ public class ActiveUser extends PeerUser { private transient PeerConnection connection; - public ActiveUser(String username, InetAddress ipAddr) { + public ActiveUser(String username, InetAddress ipAddr) throws IOException { super(username); connection = new PeerConnection(ipAddr); } @@ -19,6 +20,7 @@ public class ActiveUser extends PeerUser { * @param message */ public void sendMessage(Message message) { +// connection.sendMessage(message); } diff --git a/src/main/java/fr/insa/clavardator/users/UserList.java b/src/main/java/fr/insa/clavardator/users/UserList.java index a965e6a..c46c8d3 100644 --- a/src/main/java/fr/insa/clavardator/users/UserList.java +++ b/src/main/java/fr/insa/clavardator/users/UserList.java @@ -2,9 +2,11 @@ package fr.insa.clavardator.users; import fr.insa.clavardator.db.DatabaseController; import fr.insa.clavardator.network.NetDiscoverer; +import fr.insa.clavardator.util.ErrorCallback; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.io.IOException; import java.util.ArrayList; import java.util.function.Predicate; @@ -47,12 +49,17 @@ public class UserList { /** * */ - public void discoverActiveUsers() { + public void discoverActiveUsers(ErrorCallback errorCallback) { NetDiscoverer.discoverActiveUsers("CLAVARDATOR_BROADCAST", (ipAddr, data) -> { - ActiveUser newUser = new ActiveUser("", ipAddr); // TODO find username + ActiveUser newUser = null; + try { + newUser = new ActiveUser("", ipAddr); // TODO find username + } catch (IOException e) { + errorCallback.onError(e); + } activeUsers.add(newUser); pcs.firePropertyChange("activeUsers", null, newUser); - }); + }, errorCallback); } } diff --git a/src/main/java/fr/insa/clavardator/util/ErrorCallback.java b/src/main/java/fr/insa/clavardator/util/ErrorCallback.java new file mode 100644 index 0000000..3b7d8b1 --- /dev/null +++ b/src/main/java/fr/insa/clavardator/util/ErrorCallback.java @@ -0,0 +1,5 @@ +package fr.insa.clavardator.util; + +public interface ErrorCallback { + void onError(Exception e); +} diff --git a/src/main/java/fr/insa/clavardator/util/ErrorHandler.java b/src/main/java/fr/insa/clavardator/util/ErrorHandler.java index 5c762b0..158c933 100644 --- a/src/main/java/fr/insa/clavardator/util/ErrorHandler.java +++ b/src/main/java/fr/insa/clavardator/util/ErrorHandler.java @@ -3,6 +3,7 @@ package fr.insa.clavardator.util; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +@Deprecated public class ErrorHandler { private ErrorHandler() {}