From 7168431bcdd566680e79dadb5fdb6d883e5b39db Mon Sep 17 00:00:00 2001 From: GustavoHMDS Date: Mon, 28 Sep 2026 10:33:09 -0300 Subject: [PATCH] WIP --- pitiupi/src/pitiupi/GUI/MainWindow.java | 119 +++---------- pitiupi/src/pitiupi/GUI/MenuBar.java | 2 +- .../pitiupi/control/ConnectionManager.java | 104 +++++++++++ .../src/pitiupi/control/HeartbeatManager.java | 12 +- pitiupi/src/pitiupi/control/PluginLoader.java | 53 +++--- .../src/pitiupi/control/PluginManager.java | 71 ++++++++ pitiupi/src/pitiupi/net/tcp/SocketTCP.java | 167 ++++++++---------- ...Manager.java => TcpConnectionManager.java} | 4 +- pitiupi/src/pitiupi/net/udp/SocketUDP.java | 51 +++--- 9 files changed, 339 insertions(+), 244 deletions(-) create mode 100644 pitiupi/src/pitiupi/control/ConnectionManager.java create mode 100644 pitiupi/src/pitiupi/control/PluginManager.java rename pitiupi/src/pitiupi/net/tcp/{ConnectionManager.java => TcpConnectionManager.java} (99%) diff --git a/pitiupi/src/pitiupi/GUI/MainWindow.java b/pitiupi/src/pitiupi/GUI/MainWindow.java index cc72db4..9d99aa7 100644 --- a/pitiupi/src/pitiupi/GUI/MainWindow.java +++ b/pitiupi/src/pitiupi/GUI/MainWindow.java @@ -5,13 +5,11 @@ */ package pitiupi.GUI; -import pitiupi.net.tcp.SocketTCP; -import pitiupi.net.udp.SocketUDP; -import java.util.ArrayList; -import java.util.List; +import pitiupi.control.ConnectionManager; +import pitiupi.control.PluginManager; + import javax.swing.JMenu; -import pitiupi.control.PluginLoader; -import pitiupi.plugin.Plugin; + import pitiupi.control.HeartbeatManager; /** @@ -36,20 +34,12 @@ public class MainWindow extends javax.swing.JFrame { private javax.swing.JPanel statusPanel; private javax.swing.JTabbedPane tabbedPane; - private HeartbeatManager heartbeatManager; private OnlineUsersPanel onlineUsersPanel; - - private SocketUDP socketUDP; - private SocketTCP socketTCP; - private String userName; - private int port; - private String pitiupiIdentifier; - - private PluginLoader pluginManager; - private final List plugins; + private ConnectionManager connectionManager; + private PluginManager pluginManager; /** * Cria a janela principal da aplicação. @@ -59,22 +49,18 @@ public class MainWindow extends javax.swing.JFrame { */ public MainWindow(String userName, int port) { this.userName = userName; - this.port = port; - this.pitiupiIdentifier = "Pitiupi.Alice.2026"; - this.menuBar = new MenuBar(this); - this.plugins = new ArrayList<>(); - this.initComponents(); + + pluginManager = new PluginManager(this); + loadPlugins(); + + connectionManager = new ConnectionManager(this, pluginManager, port); + + menuBar = new MenuBar(this); + + initComponents(); } private void initComponents() { - initGUI(); - initSocket(); - initHeartbeat(); - initPlugins(); - this.setSize(new java.awt.Dimension(1024, 768)); - } - - private void initGUI() { this.setJMenuBar(menuBar); this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); this.setTitle("Share My Sheet"); @@ -86,34 +72,19 @@ public class MainWindow extends javax.swing.JFrame { jScrollPane1.setViewportView(tabbedPane); statusPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT)); - status.setText("Connected on port " + this.port + " name " + this.userName); + updateStatus(); statusPanel.add(status); this.getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER); this.getContentPane().add(statusPanel, java.awt.BorderLayout.PAGE_END); - this.pack(); - } - - private void initSocket() { - this.socketUDP = new SocketUDP(this); - this.socketTCP = new SocketTCP(this); - - this.socketUDP.start(); - this.socketTCP.start(); - } - - private void initHeartbeat() { - this.heartbeatManager = new HeartbeatManager(this); this.onlineUsersPanel = new OnlineUsersPanel(); - this.heartbeatManager.addPeerListener(this.onlineUsersPanel); + this.connectionManager.addPeerListener(onlineUsersPanel); this.getContentPane().add(this.onlineUsersPanel, java.awt.BorderLayout.LINE_END); - this.heartbeatManager.start(); - } - private void initPlugins() { - this.pluginManager = new PluginLoader(this); - this.pluginManager.loadPlugins(); + this.pack(); + + this.setSize(new java.awt.Dimension(1024, 768)); } public void exit() { @@ -122,65 +93,29 @@ public class MainWindow extends javax.swing.JFrame { System.exit(0); } - public HeartbeatManager getHeartbeatManager() { - return heartbeatManager; - } - public String getUserName(){ return this.userName; } - public String getIdentifier(){ - return this.pitiupiIdentifier; + public ConnectionManager getConnectionManager() { + return connectionManager; + } + + public void loadPlugins() { + pluginManager.loadPlugins(); } public void addMenu(JMenu menu) { this.menuBar.addPlugin(menu); } - public int getPort() { - return this.port; - } - - public SocketUDP getSocketUDP() { - return this.socketUDP; - } - - public SocketTCP getSocketTCP() { - return this.socketTCP; - } - - public List getPlugins() { - return plugins; - } - public void setUserName(String userName) { this.userName = userName; updateStatus(); } - public void setPort(int port) { - this.port = port; - reconnect(); - updateStatus(); - } - private void updateStatus() { - this.status.setText("Connected on port " + this.port + " name " + this.userName); + this.status.setText("Connected on port " + connectionManager + " name " + this.userName); } - private void reconnect() { - if (this.socketUDP != null) { - this.socketUDP.close(); - } - if (this.socketTCP != null) { - this.socketTCP.close(); - } - - this.socketUDP = new SocketUDP(this); - this.socketTCP = new SocketTCP(this); - - this.socketUDP.start(); - this.socketTCP.start(); - } } diff --git a/pitiupi/src/pitiupi/GUI/MenuBar.java b/pitiupi/src/pitiupi/GUI/MenuBar.java index db4ca35..4e517a8 100644 --- a/pitiupi/src/pitiupi/GUI/MenuBar.java +++ b/pitiupi/src/pitiupi/GUI/MenuBar.java @@ -80,7 +80,7 @@ public class MenuBar extends JMenuBar { login.setVisible(true); mainWindow.setUserName(login.getName()); - mainWindow.setPort(login.getPort()); + mainWindow.getConnectionManager().setPort(login.getPort()); login.dispose(); } diff --git a/pitiupi/src/pitiupi/control/ConnectionManager.java b/pitiupi/src/pitiupi/control/ConnectionManager.java new file mode 100644 index 0000000..4b744d8 --- /dev/null +++ b/pitiupi/src/pitiupi/control/ConnectionManager.java @@ -0,0 +1,104 @@ +package pitiupi.control; + +import pitiupi.GUI.MainWindow; +import pitiupi.net.HeartbeatMessage; +import pitiupi.net.Message; +import pitiupi.net.tcp.SocketTCP; +import pitiupi.net.tcp.TcpConnection; +import pitiupi.net.udp.SocketUDP; + +import java.net.InetAddress; + +public class ConnectionManager { + private final String pitiupiIdentifier; + + private PluginManager pluginManager; + + private HeartbeatManager heartbeatManager; + + private SocketTCP socketTCP; + private SocketUDP socketUDP; + private int port; + + public ConnectionManager(MainWindow main, PluginManager pluginManager, int port) { + this.pluginManager = pluginManager; + this.port = port; + + pitiupiIdentifier = "Pitiupi.Alice.2026"; + + reconnect(); + + heartbeatManager = new HeartbeatManager(main, this); + heartbeatManager.start(); + } + + public TcpConnection connectPluginTcp(InetAddress destinationAdress, String senderId, String receiverId) { + return socketTCP.createPrivateConnection(destinationAdress, senderId, receiverId); + } + + public boolean sendTcp(Message message, InetAddress destinationAddress) { + return socketTCP.send(message, destinationAddress); + } + + public boolean sendUdpUnicast(Message message, InetAddress destinationAddress) { + try { + socketUDP.sendUnicast(message, destinationAddress); + return true; + } catch (Exception ex) { + return false; + } + } + + public boolean sendUdpMulticast(Message message) { + try { + socketUDP.sendMulticast(message); + return true; + } catch (Exception ex) { + return false; + } + } + + public void broadcastLocal(Message message) { + pluginManager.handlePublicMessage(message); + } + + public boolean sendLocal(byte[] message, String receiverId) { + return pluginManager.handlePrivateMessage(message, receiverId); + } + + public void addPeerListener(PeerListener peerListener) { + heartbeatManager.addPeerListener(peerListener); + } + + public void receiveHeartbeat(HeartbeatMessage message, InetAddress destinationAddress) { + heartbeatManager.receiveHeartbeat(message, destinationAddress); + } + + public void setPort(int port) { + this.port = port; + reconnect(); + } + + public int getPort() { + return port; + } + + public String getIdentifier(){ + return this.pitiupiIdentifier; + } + + private void reconnect() { + if (this.socketUDP != null) { + this.socketUDP.close(); + } + if (this.socketTCP != null) { + this.socketTCP.close(); + } + + this.socketUDP = new SocketUDP(this, pluginManager); + this.socketTCP = new SocketTCP(this, pluginManager); + + this.socketUDP.start(); + this.socketTCP.start(); + } +} diff --git a/pitiupi/src/pitiupi/control/HeartbeatManager.java b/pitiupi/src/pitiupi/control/HeartbeatManager.java index 1cfa480..bbdf84e 100644 --- a/pitiupi/src/pitiupi/control/HeartbeatManager.java +++ b/pitiupi/src/pitiupi/control/HeartbeatManager.java @@ -30,6 +30,7 @@ public class HeartbeatManager { private static final long PEER_TIMEOUT_MS = 15000; // ~3 batimentos perdidos private final MainWindow mainWindow; + private final ConnectionManager connectionManager; private final Map peers = new ConcurrentHashMap<>(); private final List listeners = new CopyOnWriteArrayList<>(); private ScheduledExecutorService scheduler; @@ -41,8 +42,9 @@ public class HeartbeatManager { * @param mainWindow janela principal utilizada para obter o nome do usuário * e o socket de comunicação. */ - public HeartbeatManager(MainWindow mainWindow) { + public HeartbeatManager(MainWindow mainWindow, ConnectionManager connectionManager) { this.mainWindow = mainWindow; + this.connectionManager = connectionManager; } /** @@ -64,12 +66,8 @@ public class HeartbeatManager { } private void announce() { - try { - HeartbeatMessage msg = new HeartbeatMessage(mainWindow.getUserName(), instanceId); - mainWindow.getSocketUDP().sendMulticast(msg.toByteArray()); - } catch (IOException ex) { - Logger.getLogger(HeartbeatManager.class.getName()).log(Level.WARNING, "Falha ao enviar heartbeat", ex); - } + HeartbeatMessage msg = new HeartbeatMessage(mainWindow.getUserName(), instanceId); + connectionManager.sendUdpMulticast(msg); } // Chamado pelo Socket quando um pacote é identificado como heartbeat diff --git a/pitiupi/src/pitiupi/control/PluginLoader.java b/pitiupi/src/pitiupi/control/PluginLoader.java index db549e4..7a40dd9 100644 --- a/pitiupi/src/pitiupi/control/PluginLoader.java +++ b/pitiupi/src/pitiupi/control/PluginLoader.java @@ -4,14 +4,12 @@ */ package pitiupi.control; -import java.awt.List; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.ServiceLoader; -import java.util.Vector; +import java.util.*; + import pitiupi.GUI.MainWindow; import pitiupi.Main; import pitiupi.plugin.Plugin; @@ -33,7 +31,7 @@ public class PluginLoader { this.mainWindow = main; } - public void loadPlugins() { + public void loadPlugins(List plugins, HashSet loadedJars) { File pluginDir = new File("plugins"); File[] jarFiles = pluginDir.listFiles((dir, name) -> name.endsWith(".jar")); @@ -42,33 +40,34 @@ public class PluginLoader { return; } - try { - // 2. Convert jar file paths into URLs - ArrayList urls = new ArrayList(); - for (File file : jarFiles) { - urls.add(file.toURI().toURL()); - System.out.println("Discovered plugin package: " + file.getName()); + for (File file : jarFiles) { + + if (loadedJars.contains(file.getName())) { + continue; } - // 3. Create a class loader isolated from the application's default loader - URLClassLoader pluginClassLoader = new URLClassLoader( - (URL[])urls.toArray(new URL[0]), - Main.class.getClassLoader() - ); - System.out.println(pluginClassLoader); + System.out.println("Discovered plugin package: " + file.getName()); - // 4. Locate and instantiate all classes implementing the Plugin interface - ServiceLoader serviceLoader = ServiceLoader.load(Plugin.class, pluginClassLoader); + try { + URLClassLoader classLoader = new URLClassLoader( + new URL[]{file.toURI().toURL()}, + Main.class.getClassLoader() + ); - System.out.println("\n--- Executing Discovered Plugins ---" + serviceLoader.findFirst()); - for (Plugin plugin : serviceLoader) { - System.out.println("Loading: " + plugin.getName()); - plugin.createPlugin(this.mainWindow); - this.mainWindow.getPlugins().add(plugin); + ServiceLoader serviceLoader = ServiceLoader.load(Plugin.class, classLoader); + + for (Plugin plugin : serviceLoader) { + System.out.println("Loading: " + plugin.getName()); + + plugin.createPlugin(this.mainWindow); + plugins.add(plugin); + loadedJars.add(file.getName()); + } + + } catch (Exception e) { + System.out.println("Failed to load plugin " + file.getName()); + e.printStackTrace(); } - - } catch (MalformedURLException e) { - System.out.println(e.toString()); } } } diff --git a/pitiupi/src/pitiupi/control/PluginManager.java b/pitiupi/src/pitiupi/control/PluginManager.java new file mode 100644 index 0000000..08ea55c --- /dev/null +++ b/pitiupi/src/pitiupi/control/PluginManager.java @@ -0,0 +1,71 @@ +package pitiupi.control; + +import pitiupi.GUI.MainWindow; +import pitiupi.net.Message; +import pitiupi.net.tcp.TcpConnection; +import pitiupi.plugin.Plugin; +import pitiupi.plugin.PrivateConnectionPlugin; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +public class PluginManager { + private PluginLoader pluginLoader; + private final List plugins; + private final HashSet loadedJars; + + public PluginManager(MainWindow main) { + this.pluginLoader = new PluginLoader(main); + this.plugins = new ArrayList<>(); + this.loadedJars = new HashSet<>(); + } + + public void loadPlugins() { + pluginLoader.loadPlugins(plugins, loadedJars); + } + + public void handlePublicMessage(Message msg) { + for (Plugin plugin : plugins) { + plugin.receiveMessage(msg); + } + } + + private Plugin getPlugin(String pluginId) { + for (Plugin plugin : plugins) { + if (plugin.getIdentifier().equals(pluginId)) return plugin; + } + return null; + } + + public boolean handlePrivateMessage(byte[] msg, String receiverId) { + Plugin plugin = getPlugin(receiverId); + if (plugin == null) return false; + + if (plugin instanceof PrivateConnectionPlugin privatePlugin) { + privatePlugin.receiveBytes(msg); + return true; + } + + return false; + } + + public boolean handleConnection(TcpConnection connection, String receiverId) { + Plugin plugin = getPlugin(receiverId); + if (plugin == null) return false; + + if (plugin instanceof PrivateConnectionPlugin privatePlugin) { + privatePlugin.receivePrivateConnection(connection); + return true; + } + + return false; + } + + public void handleDisconnection(TcpConnection connection, String receiverId) { + Plugin plugin = getPlugin(receiverId); + if (plugin instanceof PrivateConnectionPlugin privatePlugin) { + privatePlugin.onSocketClosed(connection); + } + } +} diff --git a/pitiupi/src/pitiupi/net/tcp/SocketTCP.java b/pitiupi/src/pitiupi/net/tcp/SocketTCP.java index 920dffa..9033903 100644 --- a/pitiupi/src/pitiupi/net/tcp/SocketTCP.java +++ b/pitiupi/src/pitiupi/net/tcp/SocketTCP.java @@ -1,11 +1,12 @@ package pitiupi.net.tcp; import pitiupi.GUI.MainWindow; +import pitiupi.control.ConnectionManager; +import pitiupi.control.PluginManager; import pitiupi.net.Message; import pitiupi.plugin.Plugin; import pitiupi.plugin.PrivateConnectionPlugin; -import javax.swing.*; import java.io.*; import java.net.*; import java.util.Objects; @@ -35,12 +36,13 @@ public class SocketTCP extends Thread { private final ExecutorService connectionExecutor = Executors.newCachedThreadPool(); - private final ConnectionManager connectionManager; + private final TcpConnectionManager tcpConnectionManager; private ServerSocket serverSocket; private InetAddress address; - private final MainWindow main; + private final ConnectionManager connectionManager; + private final PluginManager pluginManager; private volatile boolean running = true; @@ -51,15 +53,18 @@ public class SocketTCP extends Thread { * com os peers são estabelecidas sob demanda durante o envio ou aceitas * quando iniciadas por outros peers.

* - * @param main janela principal da aplicação, usada para obter a porta, - * o identificador local e os plugins disponíveis. + * @param connectionManager interface de conexão da aplicação, usada para obter a porta, + * o identificador local e os plugins disponíveis. */ - public SocketTCP(MainWindow main) { - this.main = main; + public SocketTCP(ConnectionManager connectionManager, PluginManager pluginManager) { + this.connectionManager = connectionManager; + this.pluginManager = pluginManager; + logger = Logger.getLogger(getClass().getName()); - connectionManager = new ConnectionManager(); + tcpConnectionManager = new TcpConnectionManager(); + try { - serverSocket = new ServerSocket(main.getPort()); + serverSocket = new ServerSocket(connectionManager.getPort()); address = InetAddress.getByName(InetAddress.getLocalHost().getHostAddress()); } catch (IOException ex) { System.out.println("There is no socket connection. Sorry."); @@ -75,28 +80,36 @@ public class SocketTCP extends Thread { * do envio. Falhas durante o estabelecimento ou envio são registradas na * saída padrão e não são propagadas ao chamador.

* - * @param msg mensagem serializada em bytes que será enviada. + * @param msg mensagem que será enviada. * @param destinationAddress endereço IP do peer que receberá a mensagem. */ - public void send(byte[] msg, InetAddress destinationAddress) { + public boolean send(Message msg, InetAddress destinationAddress) { try { - TcpConnection connection = getPublicConnection(destinationAddress, main.getIdentifier(), main.getIdentifier()); + TcpConnection connection = getPublicConnection( + destinationAddress, + connectionManager.getIdentifier(), + connectionManager.getIdentifier() + ); + if (connection == null) { System.out.println("Could not establish TCP connection."); - return; + return false; } - connection.send(msg); + + connection.send(msg.toByteArray()); } catch (Exception ex) { System.out.println("Could not send TCP message."); System.out.println(ex.toString()); + return false; } + return true; } /** * Estabelece uma conexão TCP privada com um plugin específico do peer de destino. * *

A conexão é criada como privada e passa a ser gerenciada pelo - * {@link ConnectionManager}. O método também inicia a tarefa responsável + * {@link TcpConnectionManager}. O método também inicia a tarefa responsável * por receber os dados dessa conexão.

* * @param destinationAddress endereço IP do peer de destino. @@ -115,11 +128,11 @@ public class SocketTCP extends Thread { * Obtém uma conexão TCP pública existente com o peer de destino ou estabelece * uma nova caso não exista uma conexão válida. * - *

As conexões públicas são gerenciadas pelo {@link ConnectionManager}. + *

As conexões públicas são gerenciadas pelo {@link TcpConnectionManager}. * O método primeiro verifica se já existe uma conexão pública registrada * para o endereço de destino e, caso ela exista e não esteja fechada, * reutiliza-a. Caso contrário, uma nova conexão pública é estabelecida, - * registrada no {@link ConnectionManager} e disponibilizada para uso.

+ * registrada no {@link TcpConnectionManager} e disponibilizada para uso.

* *

O acesso ao método é sincronizado para evitar que múltiplas threads * estabeleçam simultaneamente conexões públicas para o mesmo peer.

@@ -133,7 +146,7 @@ public class SocketTCP extends Thread { private synchronized TcpConnection getPublicConnection(InetAddress destinationAddress, String senderId, String receiverId) { TcpConnection connection; - connection = connectionManager.getPublicConnection(destinationAddress); + connection = tcpConnectionManager.getPublicConnection(destinationAddress); if (connection != null && !connection.isClosed()) return connection; connection = establishOutgoingConnection(destinationAddress, senderId, receiverId, false); @@ -146,7 +159,7 @@ public class SocketTCP extends Thread { * *

Cada socket aceito é encaminhado para processamento assíncrono, * interpretado como uma {@link TcpConnection}, registrado pelo - * {@link ConnectionManager} e associado ao receptor adequado.

+ * {@link TcpConnectionManager} e associado ao receptor adequado.

*/ private void receive() { while (running) { @@ -188,7 +201,7 @@ public class SocketTCP extends Thread { throw new IllegalArgumentException("Connections to the local host are forbidden."); } - TcpConnection connection = ConnectionFactory.createConnection(destinationAddress, main.getPort(), sender, receiver, isPrivate); + TcpConnection connection = ConnectionFactory.createConnection(destinationAddress, connectionManager.getPort(), sender, receiver, isPrivate); if (connection == null) return null; saveConnection(connection); @@ -229,10 +242,10 @@ public class SocketTCP extends Thread { */ private void saveConnection(TcpConnection connection) { if (connection.isPrivate()) { - connectionManager.addPrivateConnection(connection); + tcpConnectionManager.addPrivateConnection(connection); } else { - connectionManager.addPublicConnection(connection); + tcpConnectionManager.addPublicConnection(connection); } } @@ -255,48 +268,21 @@ public class SocketTCP extends Thread { return; } - if (connection.getReceiver().equals(main.getIdentifier())) { + if (connection.getReceiver().equals(connectionManager.getIdentifier())) { systemConnectionReceiver(connection); return; } - Plugin receiver = findConnectionReceiver(connection); - if (receiver instanceof PrivateConnectionPlugin plugin) { - if (notify) { - plugin.receivePrivateConnection(connection); - } - privateConnectionReceiver(connection, plugin); - } - } - - /** - * Localiza o plugin responsável por receber uma conexão privada. - * - *

A busca é feita pelo identificador do destinatário informado na - * própria conexão. Caso nenhum plugin correspondente seja encontrado, - * uma mensagem de erro é enviada ao peer remoto.

- * - * @param connection conexão privada cujo destinatário será localizado. - * @return o plugin com o identificador correspondente ao destinatário, - * ou {@code null} se nenhum plugin for encontrado. - */ - private Plugin findConnectionReceiver(TcpConnection connection) { - Plugin receiver = null; - for(Plugin plugin : main.getPlugins()) { - if (plugin.getIdentifier().equals(connection.getReceiver())) { - receiver = plugin; - break; - } - } - - if (receiver == null) { + if (pluginManager.handleConnection(connection, connection.getReceiver())) + privateConnectionReceiver(connection); + else { SysInfoMessage.sendSystemInfo( connection, SysInfoType.RECEIVER_NOT_FOUND, "This peer does not have the plugin: " + connection.getReceiver() ); } - return receiver; + } /** @@ -308,7 +294,7 @@ public class SocketTCP extends Thread { * condição de erro.

* *

O método também trata timeouts e erros de I/O, removendo a conexão - * do {@link ConnectionManager} quando ela deixa de ser utilizável.

+ * do {@link TcpConnectionManager} quando ela deixa de ser utilizável.

* * @param connection conexão pública da qual as mensagens serão recebidas. */ @@ -324,15 +310,13 @@ public class SocketTCP extends Thread { SysInfoMessage sysMessage = SysInfoMessage.parseSystemInfo(message); if (sysMessage == null) { - for (Plugin plugin : main.getPlugins()) { - plugin.receiveMessage(message); - } + pluginManager.handlePublicMessage(message); continue; } switch (sysMessage.getType()) { case CONNECTION_CLOSED, INTERNAL_ERROR -> { - connectionManager.closeConnection(connection); + tcpConnectionManager.closeConnection(connection); return; } case MESSAGE_REJECTED -> { @@ -356,17 +340,17 @@ public class SocketTCP extends Thread { "class Message not found." ); logger.log(Level.SEVERE, null, ex); - connectionManager.closeConnection(connection); + tcpConnectionManager.closeConnection(connection); } } catch (SocketTimeoutException ex) { if (connection.hasTimedOut()) { - connectionManager.closeConnection(connection, "Connection timeout"); + tcpConnectionManager.closeConnection(connection, "Connection timeout"); return; } } catch (IOException ex) { - connectionManager.closeConnection(connection); + tcpConnectionManager.closeConnection(connection); } } } @@ -381,40 +365,37 @@ public class SocketTCP extends Thread { * do plugin e o fechamento da conexão.

* * @param connection conexão privada da qual os dados serão recebidos. - * @param plugin plugin responsável pelo processamento dos dados recebidos. */ - private void privateConnectionReceiver(TcpConnection connection, Plugin plugin) { - if (plugin instanceof PrivateConnectionPlugin privatePlugin) { - while (running) { - try { - byte[] message = connection.receive(); - SysInfoMessage sysMessage = SysInfoMessage.parseSystemInfo(message); + private void privateConnectionReceiver(TcpConnection connection) { + while (running) { + try { + byte[] message = connection.receive(); + SysInfoMessage sysMessage = SysInfoMessage.parseSystemInfo(message); - if (sysMessage == null) { - privatePlugin.receiveBytes(message); + if (sysMessage == null) { + pluginManager.handlePrivateMessage(message, connection.getReceiver()); + continue; + } + + switch (sysMessage.getType()) { + case CONNECTION_CLOSED, INTERNAL_ERROR -> { + pluginManager.handleDisconnection(connection, connection.getReceiver()); + tcpConnectionManager.closeConnection(connection); + } + default -> { continue; } - - switch (sysMessage.getType()) { - case CONNECTION_CLOSED, INTERNAL_ERROR -> { - privatePlugin.onSocketClosed(connection); - connectionManager.closeConnection(connection); - } - default -> { - continue; - } - } } - catch (SocketTimeoutException ex) { - if (connection.hasTimedOut()) { - connectionManager.closeConnection(connection, "Connection timeout"); - return; - } - } - catch (IOException ex) { - connectionManager.closeConnection(connection); + } + catch (SocketTimeoutException ex) { + if (connection.hasTimedOut()) { + tcpConnectionManager.closeConnection(connection, "Connection timeout"); + return; } } + catch (IOException ex) { + tcpConnectionManager.closeConnection(connection); + } } } @@ -445,7 +426,7 @@ public class SocketTCP extends Thread { if (connection.hasTimedOut()) return; } catch (IOException ex) { - connectionManager.closeConnection(connection); + tcpConnectionManager.closeConnection(connection); } } } @@ -454,13 +435,13 @@ public class SocketTCP extends Thread { * Encerra uma conexão TCP e registra o motivo informado. * *

Quando nenhuma descrição é fornecida, é utilizado um motivo padrão. - * O fechamento efetivo da conexão é delegado ao {@link ConnectionManager}.

+ * O fechamento efetivo da conexão é delegado ao {@link TcpConnectionManager}.

* * @param connection conexão que será encerrada. * @param description motivo do encerramento; pode ser {@code null}. */ public void disconnect(TcpConnection connection, String description) { - connectionManager.closeConnection( + tcpConnectionManager.closeConnection( connection, Objects.requireNonNullElse(description, "No reason provided") ); @@ -493,7 +474,7 @@ public class SocketTCP extends Thread { } } - connectionManager.closeAllConnections("The peer must have closed the application or changed ports"); + tcpConnectionManager.closeAllConnections("The peer must have closed the application or changed ports"); connectionExecutor.shutdownNow(); } diff --git a/pitiupi/src/pitiupi/net/tcp/ConnectionManager.java b/pitiupi/src/pitiupi/net/tcp/TcpConnectionManager.java similarity index 99% rename from pitiupi/src/pitiupi/net/tcp/ConnectionManager.java rename to pitiupi/src/pitiupi/net/tcp/TcpConnectionManager.java index b8b774c..a8df7db 100644 --- a/pitiupi/src/pitiupi/net/tcp/ConnectionManager.java +++ b/pitiupi/src/pitiupi/net/tcp/TcpConnectionManager.java @@ -27,7 +27,7 @@ import java.util.stream.Collectors; * peers ativos para encerrar conexões associadas a peers que deixaram de * estar disponíveis.

*/ -class ConnectionManager implements PeerListener { +class TcpConnectionManager implements PeerListener { private final Logger logger; private final Map publicConnections; private final Map> privateConnections; @@ -35,7 +35,7 @@ class ConnectionManager implements PeerListener { /** * Cria um gerenciador de conexões TCP vazio. */ - public ConnectionManager() { + public TcpConnectionManager() { publicConnections = new ConcurrentHashMap<>(); privateConnections = new ConcurrentHashMap<>(); diff --git a/pitiupi/src/pitiupi/net/udp/SocketUDP.java b/pitiupi/src/pitiupi/net/udp/SocketUDP.java index da9fa5f..6389cad 100644 --- a/pitiupi/src/pitiupi/net/udp/SocketUDP.java +++ b/pitiupi/src/pitiupi/net/udp/SocketUDP.java @@ -14,6 +14,8 @@ import java.net.*; import java.util.logging.Level; import java.util.logging.Logger; +import pitiupi.control.ConnectionManager; +import pitiupi.control.PluginManager; import pitiupi.net.HeartbeatMessage; import pitiupi.net.Message; import pitiupi.plugin.Plugin; @@ -37,7 +39,10 @@ public class SocketUDP extends Thread { private MulticastSocket multicastSocket; private InetAddress address; - private MainWindow main; + + private ConnectionManager connectionManager; + private PluginManager pluginManager; + private volatile boolean running = true; public final static String INET_ADDR = "224.0.0.3"; @@ -47,22 +52,26 @@ public class SocketUDP extends Thread { *

O socket é associado à porta da aplicação e ingressa no grupo * multicast configurado.

* - * @param main janela principal da aplicação. + * @param connectionManager interface que gerencia toda conexão da aplicação. + * @param pluginManager interface que gerencia os plugins da conexão. */ - public SocketUDP(MainWindow main) { - this.main = main; + public SocketUDP(ConnectionManager connectionManager, PluginManager pluginManager) { + this.connectionManager = connectionManager; + this.pluginManager = pluginManager; + try { this.address = InetAddress.getByName(SocketUDP.INET_ADDR); - } catch (UnknownHostException ex) { - System.getLogger(SocketUDP.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); - } - try { - multicastSocket = new MulticastSocket(this.main.getPort()); + + multicastSocket = new MulticastSocket(connectionManager.getPort()); multicastSocket.setSendBufferSize(256000); multicastSocket.setReceiveBufferSize(256000); multicastSocket.setReuseAddress(true); multicastSocket.joinGroup(address); - } catch (IOException ex) { + } + catch (UnknownHostException ex) { + System.getLogger(SocketUDP.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex); + } + catch (IOException ex) { System.out.println("There is no socket connection. Sorry."); System.out.println(ex); } @@ -71,22 +80,22 @@ public class SocketUDP extends Thread { /** * Envia uma mensagem para o grupo multicast da aplicação. * - * @param msg mensagem serializada a ser enviada. + * @param msg mensagem a ser enviada. * @throws IOException caso ocorra um erro durante o envio. */ - public void sendMulticast(byte[] msg) throws IOException { - send(msg, this.address); + public void sendMulticast(Message msg) throws IOException { + send(msg.toByteArray(), this.address); } /** * Envia uma mensagem diretamente para um peer utilizando UDP. * - * @param msg mensagem serializada a ser enviada. + * @param msg mensagem a ser enviada. * @param destinationAddress endereço IP do peer destinatário. * @throws IOException caso ocorra um erro durante o envio. */ - public void sendUnicast(byte[] msg, InetAddress destinationAddress) throws IOException { - send(msg, destinationAddress); + public void sendUnicast(Message msg, InetAddress destinationAddress) throws IOException { + send(msg.toByteArray(), destinationAddress); } /** @@ -98,7 +107,7 @@ public class SocketUDP extends Thread { */ private void send(byte[] msg, InetAddress destinationAddress) throws IOException { DatagramPacket msgPacket; - msgPacket = new DatagramPacket(msg, msg.length, destinationAddress, this.main.getPort()); + msgPacket = new DatagramPacket(msg, msg.length, destinationAddress, connectionManager.getPort()); multicastSocket.send(msgPacket); } @@ -145,7 +154,7 @@ public class SocketUDP extends Thread { } HeartbeatMessage heartbeat = tryParseHeartbeat(msgPacket.getData()); if (heartbeat != null) { - main.getHeartbeatManager().receiveHeartbeat(heartbeat, msgPacket.getAddress()); + connectionManager.receiveHeartbeat(heartbeat, msgPacket.getAddress()); continue; } @@ -154,10 +163,8 @@ public class SocketUDP extends Thread { continue; } - for (Plugin plugin : main.getPlugins()) { - System.out.println(msgPacket.getAddress().toString()); - plugin.receiveMessage(message); - } + System.out.println(msgPacket.getAddress().toString()); + pluginManager.handlePublicMessage(message); } }