Author SHA1 Message Date
Gustavo a628490fcb atualizar tutorial de plugins 2026-10-07 12:04:10 -03:00
Gustavo 395363e4bd Atualizei o tutorial de criação de plugins 2026-10-06 12:24:47 -03:00
GustavoHMDS 12497594e4 Correcao de bug e comeco da documentacao 2026-10-05 15:03:24 -03:00
tonyhcj 6a597092fe fix: corrige chaves desencontradas em GuiManager.buildMenu
Um bloco do if (menu instanceof UnicastSubMenu) estava duplicado e
incompleto (sobrava um fragmento com reticências soltas), o que
impedia a compilação do núcleo. Remove a duplicação, mantendo só
o bloco correto e completo que já existia logo depois.
2026-10-03 20:11:17 -03:00
tonyhcj ffd474e7ff docs: atualiza README 2026-10-03 16:55:08 -03:00
tonyhcj 4d39648ee7 docs: atualiza README 2026-10-03 16:51:29 -03:00
tonyhcj 095af14463 fix: remove build/ do controle de versão 2026-10-03 16:32:26 -03:00
tonyhcj d0083e8069 refactor: ChatPlugin usa Pitiupi 2026-10-03 16:10:10 -03:00
tonyhcj dda324228f refactor: ChatWindow usa Pitiupi 2026-10-03 16:10:05 -03:00
tonyhcj 840183ee9f refactor: injeta Pitiupi nos plugins 2026-10-03 16:09:55 -03:00
tonyhcj eb3ce132cd refactor: Plugin usa fachada Pitiupi 2026-10-03 16:09:49 -03:00
tonyhcj d1dc427185 feat: cria fachada Pitiupi 2026-10-03 16:09:44 -03:00
31 changed files with 715 additions and 133 deletions

No files matched your search

+3 -9
View File
@@ -1,9 +1,3 @@
/pitiupi/build/
/pitiupi/dist/
/pitiupi.chat/build/
/pitiupi.chat/dist/
/pitiupi.chat/nbproject/private/
/pitiupi.screenCast/build/
/pitiupi.screenCast/dist/
.idea/
build/
dist/
*.class
+10
View File
@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+9
View File
@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="pitiupi">
<CLASSES>
<root url="jar://$PROJECT_DIR$/pitiupi.screenCast/dist/lib/pitiupi.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+9
View File
@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="pitiupi.chat">
<CLASSES>
<root url="jar://$PROJECT_DIR$/pitiupi.chat/dist/pitiupi.chat.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+9
View File
@@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="pitiupi.screenCast">
<CLASSES>
<root url="jar://$PROJECT_DIR$/pitiupi.screenCast/dist/pitiupi.screenCast.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+10
View File
@@ -0,0 +1,10 @@
<component name="libraryTable">
<library name="plugins">
<CLASSES>
<root url="jar://$PROJECT_DIR$/pitiupi/plugins/pitiupi.screenCast.jar!/" />
<root url="jar://$PROJECT_DIR$/pitiupi/plugins/pitiupi.chat.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="openjdk-27" project-jdk-type="JavaSDK" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/pitiupi.iml" filepath="$PROJECT_DIR$/.idea/pitiupi.iml" />
</modules>
</component>
</project>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+23 -3
View File
@@ -1,10 +1,13 @@
# pitiupi
Ferramenta p2p para práticas em rede
Este repositório tem 4 projetos Java que são independentes:
Este repositório tem 3 projetos Java que são independentes:
### Sistema:
- A ferramenta pitiupi (P2P)
### Plugins:
- Um plugin de Chat
- Um plugin de Chat multiprotocolo (TCP/UDP)
- Um plugin de ScreenCast
Cada um destes projetos deve ser compilado individualmente. Para isso, use a ferramenta ant no diretório do projeto.
@@ -21,9 +24,26 @@ Para criar links simbólicos no Linux, use o comando:
```
cd pitiupi/plugins
ln -s ../../pitiupi.chat/dist/*.jar .
ln -s ../../pitiupi.mpChat/dist/*.jar .
ln -s ../../pitiupi.screenCast/dist/*.jar .
```
Isso deve resolver!
Para criar um novo plugin:
## Como um plugin conversa com o pitiupi
Um plugin nunca recebe acesso direto às classes internas do núcleo (ConnectionManager, GuiManager). Em vez disso, recebe uma facade, a classe Pitiupi, que expõe só o que um plugin precisa: enviar mensagem (multicast, unicast ou tcp), abrir conexão tcp privada, ler nome de usuário e porta, criar menu.
```java
public abstract void createPlugin(Pitiupi pitiupi);
```
## Para criar um novo plugin
1. Implemente `pitiupi.models.Plugin`, incluindo `createPlugin(Pitiupi pitiupi)`
2. Registre a classe em `src/META-INF/services/pitiupi.models.Plugin`, com o nome completo da classe numa linha
3. Compile com `ant jar`
4. Linke o `.jar` em `pitiupi/plugins`
Use `pitiupi.chat` como referência — é o exemplo mais simples e completo.
Plugins que ainda não foram atualizados para a Pitiupi (como uma versão mais antiga do screenCast) não compilam contra o núcleo atual e precisam de migração antes de serem usados.
-6
View File
@@ -1,6 +0,0 @@
#Fri, 02 Oct 2026 20:11:21 -0300
C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi.chat=
C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi=
@@ -1 +0,0 @@
pitiupi.chat.plugin.ChatPlugin
+2 -2
View File
@@ -47,8 +47,8 @@ javac.modulepath=
javac.processormodulepath=
javac.processorpath=\
${javac.classpath}
javac.source=25
javac.target=25
javac.source=17
javac.target=17
javac.test.classpath=\
${javac.classpath}:\
${build.classes.dir}
@@ -8,13 +8,13 @@ package pitiupi.chat.GUI;
import java.text.SimpleDateFormat;
import java.util.Date;
import pitiupi.chat.net.ChatMessage;
import pitiupi.control.ConnectionManager;
import pitiupi.plugin.Pitiupi;
import pitiupi.models.Messages.Message;
import javax.swing.*;
/**
*
* @author tony
* @author flavio
*/
public class ChatWindow extends JDialog {
@@ -28,13 +28,12 @@ public class ChatWindow extends JDialog {
private JSplitPane jSplitPane1;
private JTextArea jTextArea1;
private final ConnectionManager connectionManager;
public ChatWindow(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
initComponents();
}
private final Pitiupi pitiupi;
public ChatWindow(Pitiupi pitiupi) {
this.pitiupi = pitiupi;
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
@@ -93,13 +92,13 @@ public class ChatWindow extends JDialog {
if (jTextArea1.getText().trim().isEmpty()) {
return;
}
ChatMessage message = new ChatMessage(connectionManager.getUserName(), jTextArea1.getText());
ChatMessage message = new ChatMessage(pitiupi.getUserName(), jTextArea1.getText());
this.sendChatMessage(message);
jTextArea1.setText("");
}
public void sendChatMessage(Message message) {
connectionManager.sendUdpMulticast(message);
pitiupi.sendUdpMulticast(message);
}
public void receiveChatMessage(ChatMessage message) {
@@ -8,29 +8,29 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import pitiupi.plugin.Pitiupi;
import pitiupi.chat.GUI.ChatMenu;
import pitiupi.chat.GUI.ChatWindow;
import pitiupi.chat.net.ChatMessage;
import pitiupi.control.ConnectionManager;
import pitiupi.control.GuiManager;
import pitiupi.models.Menus.MenuCategory;
import pitiupi.models.Messages.Message;
import pitiupi.models.Plugin;
/**
*
*@author tony
* @author flavio
*/
public class ChatPlugin extends Plugin {
private ChatWindow chatWindow;
@Override
public void createPlugin(ConnectionManager connectionManager, GuiManager guiManager) {
this.chatWindow = new ChatWindow(connectionManager);
guiManager.createMenu(MenuCategory.Social, new ChatMenu(chatWindow));
@Override
public void createPlugin(Pitiupi pitiupi) {
this.chatWindow = new ChatWindow(pitiupi);
pitiupi.createMenu(MenuCategory.Social, new ChatMenu(chatWindow));
}
@Override
public List<Class<? extends Message>> getMessages() {
return List.of(ChatMessage.class);
@@ -1,73 +0,0 @@
package control;
import GUI.ChatMenu;
import GUI.ChatWindow;
import GUI.PrivateChatWindow;
import GUI.PublicChatWindow;
import net.MpChatMessage;
import pitiupi.control.ConnectionManager;
import pitiupi.control.PeerListener;
import pitiupi.models.User;
import pitiupi.net.tcp.TcpConnection;
import javax.swing.*;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.List;
public class ChatController implements PeerListener {
ConnectionManager connectionManager;
ChatMenu chatMenu;
PublicChatWindow publicChatWindow;
private final HashMap<TcpConnection, ChatWindow> chatWindows;
public ChatController(ConnectionManager connectionManager, ChatMenu chatMenu) {
this.connectionManager = connectionManager;
publicChatWindow = new PublicChatWindow(connectionManager);
chatMenus = new HashMap<>();
chatWindows = new HashMap<>();
this.chatMenu = chatMenu;
this.chatMenu.newMenuItem(new JMenuItem("Show global chat"), publicChatWindow);
}
public void addChatWindow(TcpConnection tcpConnection) {
if (chatWindows.containsKey(tcpConnection)) return;
PrivateChatWindow newChat = new PrivateChatWindow(connectionManager, tcpConnection);
chatWindows.put(tcpConnection, newChat);
JMenuItem newMenuItem = new JMenuItem();
chatMenus.put(tcpConnection, newMenuItem);
newMenuItem.setText(tcpConnection.getAddress().toString());
chatMenu.newMenuItem(newMenuItem, newChat);
}
public void removeChatWindow(TcpConnection tcpConnection) {
ChatWindow removedWindow = chatWindows.remove(tcpConnection);
JMenuItem removedMenu = chatMenus.remove(tcpConnection);
chatMenu.removeMenuItem(removedMenu);
removedWindow.setVisible(false);
removedWindow.dispose();
}
public void receivePublic(MpChatMessage message) {
publicChatWindow.receiveMessage(message);
}
public void receivePrivate(TcpConnection tcpConnection, MpChatMessage message) {
chatWindows.get(tcpConnection).receiveMessage(message);
}
public void openChatWindow(InetAddress address) {
}
@Override
public void onPeersChanged(List<User> list) {
}
}
+10
View File
@@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/pitiupi.testSocket.iml" filepath="$PROJECT_DIR$/pitiupi.testSocket.iml" />
</modules>
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
+511 -1
View File
@@ -1,2 +1,512 @@
# Como criar plugins para o Share my Sheet
# Como criar plugins para o Pitiupi
Aqui serão discutidos os métodos e classes que um desenvolvedor pode ou deve usar para criar um plugin para a plataforma Pitiupi.
Alguns deles estarão marcados com um <span style="color: red;">[REF]</span>, isso indica que eles estão sendo alterados para a versão 3.0 e deixarão de existir ou vão mudar consideravelmente.
## GUI
O Pitiupi é feito usando a biblioteca Swing do Java, por isso é altamente recomendado que os plugins também a utilizem na hora de criar sua interface gráfica, porém não é obrigatório.
## Como tornar o seu plugin visível para o Pitiupi
A busca por plugins é realizada em três etapas pelo pitiupi:
1. Encontra todos os jars em `plugins`.
2. Verifica o `META-INF` dos jars para saber onde estão as implementações da classe `Plugin`.
3. Carrega o plugin no sistema.
Em relação ao `META-INF`, ele deve conter um diretório `resources` e dentro dele um arquivo contendo o nome completamente qualificado da classe `Plugin` do pitiupi: `pitiupi.models.Plugin`, por fim dentro desse arquivo você deve colocar o nome completamente qualificado de todas as classes que implementam `Plugin` do seu projeto, um em cada linha.
```
build/
|---->META-INF/resources/pitiupi.models.Plugin
|---->MeusPlugins/...
|---->MinhasMensagens/...
|---->Restante dos .class
```
```
src/MeusPlugins/MeuPrimeiroPlugin
src/MeusPlugins/MeuSegundoPlugin
...
```
### Dicas
- Faça um makefile que automaticamente mova o META-INF para o build/ quando você compilar uma nova versão caso ele esteja sendo alterado com frequência.
Ex:
```
JAR = ../pitiupi/dist/pitiupi.jar
BUILD_DIR = build
META-INF_DIR = src/META-INF
DIST = dist/mpChat.jar
SOURCES = $(shell find -name "*.java")
all:
mkdir -p "$(BUILD_DIR)"
mkdir -p "$(dir $(DIST))"
javac -cp "$(JAR)" -d "$(BUILD_DIR)" $(SOURCES)
cp -r "$(META-INF_DIR)" "$(BUILD_DIR)"
jar cf "$(DIST)" -C "$(BUILD_DIR)" .
clean:
rm -rf "$(BUILD_DIR)"/*
```
- Para a versão 3.0 será necessário fazer o mesmo processo para as implementações da classe `Message`, então se quiser deixar preparado para a nova versão adicione `pitiupi.models.Messages.Message` em `resources` e coloque nele todas suas implementações de `Message`, assim como você fez para os de `Plugin`.
## Pitiupi
A classe `Pitiupi` é a interface que o seu plugin vai receber quando for criado, ela fornece os métodos necessários para interagir com a interface gráfica e comunicação para outros peers.
### boolean sendUdpMulticast(Message message)
Envia uma mensagem multicast, retorna `boolean` indicando se teve sucesso.
### boolean sendUdpUnicast(Message message, InetAddress address)
Envia uma mensagem unicast via udp para o endereço fornecido, retorna `boolean` indicando se teve sucesso.
### boolean sendTcp(Message message, InetAddress address)
Envia uma mensagem unicast via tcp para o endereço fornecido, retorna `boolean` indicando se teve sucesso.
### <span style="color: red;">[REF]</span> TcpConnection connectTcp(InetAddress address, String senderId, String receiverId)
Pede uma conexão tcp privada para o seu plugin com outro usuário, para utilizar essa funcionalidade é necessário implementar alguns métodos opcionais em Plugin. Maisinformações serão discutidas na seção TcpConnection.
### String getUserName()
Retorna o nome do usuário conectado
### int getPort()
Retorna a porta que o usuário está usando o Pitiupi
### void createMenu(MenuCategory category, Menu menu)
Adiciona um menu ao pitiupi, category define em qual das categoria de Menus ele será adicionado: Jogos, Social, Streaming.
Os `Menus` serão discutidos em uma seção posterior.
## Classe Plugin
Essa é a classe que o pitiupi vai procurar ao carregar o seu plugin, ela define um contrato de métodos que todo plugin deve possuir.
### getName()
Indica o nome público do plugin.
### getAuthor()
Indica o nome dos desenvolvedores do plugin.
### getVersion()
Indica a versão atual do plugin.
### getIdentifier()
Indica um id que o pitiupi vai utilizar para enontrar seu plugin, por isso é importante que ele seja bem especifico para evitar que dois plugins sejam confundidos durante a comunicação. Procure usar algo como: MeuPlugin.Autor.Números
### createPlugin(Pitiupi pitiupi)
Após o pitiupi identificar e carregar o seu plugin, ele vai chamar esse método para inicializá-lo, por isso pense nele como o construtor do seu plugin, é aqui que você inicializa atributos, adiciona os menus inciais, etc.
### getMessages()
Esse método indica ao pitiupi quais tipos de mensagem seu plugin quer receber, normalmente as que ele mesmo implementar.
Nesse caso, é normal que ele faça:
```
return List.of(
SuaMensagem1.class,
SuaMensagem2.class,
...
);
```
Caso você queira que seu plugin receba todo tipo de mensagem, existe um método `receiveAllTypes()` que ele pode sobreescrever para receber todas mensagens
que não sejam consideradas privadas.
### receiveMessage(Message message)
Esse é o método que o pitiupi vai chamar quando quiser te entregar uma mensagem pelo canal publico de mensagens. Note que ele entrega uma `Message`, então é necessário que
seu plugin confira o tipo real ele mesmo. Como em:
```
if (message instanceOf MinhaMensagem minhaMensagem) {...}
```
O pitiupi garante que é uma mensagem de um tipo que o seu plugin diz aceitar.
### <span style="color: red;">[REF]</span> métodos opcionais
Os métodos a seguir possuem uma implementação padrão da própria classe que retornam false. Os três ultimos são necessários caso seu plugin deseje criar e receber conexões privadas.
### <span style="color: red;">[REF]</span> receiveAllTypes()
Indica ao Pitiupi que seu plugin deseja receber todas as mensagens publicas da plataforma, independente do tipo.
### <span style="color: red;">[REF]</span> receivePrivateConnection(TcpConnection connection)
Esse método é chamado quando o Pitiupi precisa entregar uma `TcpConnection` ao seu plugin, seja um que você pediu ou recebeu de um peer.
### <span style="color: red;">[REF]</span> receiveBytes(TcpConnection connection, byte[] bytes)
Esse método é chamado para entregar as mensagens recebidas por um `TcpConnection`, o tcpConnection no parametro indica qual a fonte da mensagem.
### <span style="color: red;">[REF]</span> onSocketClosed(TcpConnection connection)
Esse é método é chamado quando o socket de um `TcpConnection` pertencente ao plugin é fechado.
## Message
Essa é a classe abstrata que o pitiupi usa para comunicação nos canais publicos.
<span style="color: red;">[REF]</span> Ela possui um atributo isPublic que por padrão é true, mas é possível defini-lo no construtor como false caso a mensagem deva ser privada.
Essa classe implementa `Serializable` e possui um método `toByteArray` que transforma a mensagem em `byte[]`. Porém é importante notar que caso ela possua um objeto de outra classe como atributo aquela classe também deve implementar `Serializable`.
## <span style="color: red;">[REF]</span> TcpConnection
Representa uma conexão Tcp ativa para algum outro peer, mensagens enviadas por essa conexão não chegam ao canal publico e em vez disso vão direto para destinatário.
Caso fique inativa (Sem enviar ou receber mensagens) por 5 minutos a conexão é fechada automaticamente e o dono é notificado.
### <span style="color: red;">[REF]</span> void send(byte[] message)
Envia um conjunto de bytes[] para o destinatario.
Caso queira enviar uma `Message` chame o método toByteArray para transforma-la em bytes primeiro.
### <span style="color: red;">[REF]</span> boolean isClosed()
Indica se a conexão esta fechada
### <span style="color: red;">[REF]</span> InetAddress getAddress()
Retorna o endereço do peer que ela esta conectada.
### <span style="color: red;">[REF]</span> String getReceiver()
Retorna o identificador do plugin que ela esta conectada.
### <span style="color: red;">[REF]</span> getReceiver()
Retorna o identifador do plugin que pediu pela conexão.
## Menu
Essa é a classe que indica ao pitiupi que um menu deve ser adicionado a janela principal da aplicação.
Menus podem ser de dois tipos `UnicastMenu` e `MulticastMenu` com a principal diferença entre eles sendo onde eles são adicionados na janela principal. Outras mudanças serão discutidas quando for relevante nas classes a seguir.
Atualmente Menus não podem ser alterados uma vez que são adicionados, então é importante que eles sejam feitos com isso em mente.
Tem um método `String getText()` que retorna o que deve ser escrito no Menu`.
### SubMenu
Permite que o `Menu` expanda em uma nova seção de menus.
`UnicastSubMenu` o método `getMenu()` retorna `List<UnicastMenu>`
`MulticastSubMenu` o método `getMenu()` retorna `List<MulticastMenu>`
Exemplo:
```
ChatCasualMulticastMenu chatCasualMulticastMenu;
ChatEstudoMutlticastMenu chatEstudoMutlticastMenu;
...
@Override
public List<MulticastMenu> getMenus() {
return List.of(chatCasualMulticastMenu, chatEstudoMutlticastMenu);
}
```
### ActionMenu
É um `Menu` que que realiza alguma ação quando selecionado pelo usuário.
`UnicastActionMenu` o método `onClick(User user)` é chamado quando selecionado pelo usuário, recebendo como parametro o peer escolhido pelo usuário.
`MulticastActionMenu` o método `onClick()` é chamado quando selecionado pelo usuário.
Exemplo:
```
@Override
public void onClick(User user) {
callManager.openCallWindow(user);
}
```
## Exemplo de plugin no pitiupi:
### Plugin
Implementa o contrato de plugin.
Inicializa a janela principal e cria os menus.
Também define quais tipos de mensagem ele quer receber.
```
public class ChatPlugin extends Plugin {
private ChatWindow chatWindow;
@Override
public void createPlugin(Pitiupi pitiupi) {
this.chatWindow = new ChatWindow(pitiupi);
pitiupi.createMenu(MenuCategory.Social, new ChatMenu(chatWindow));
}
@Override
public List<Class<? extends Message>> getMessages() {
return List.of(ChatMessage.class);
}
@Override
public void receiveMessage(Message message) {
if (message instanceof ChatMessage msg) {
this.chatWindow.receiveChatMessage(msg);
}
}
@Override
public String getName() {
return "Chat";
}
@Override
public String getAuthor() {
return "Flávio Schiavoni";
}
@Override
public String getVersion() {
return "0";
}
@Override
public String getIdentifier() {
return "Pitiupi.Chat.Example.123456";
}
}
```
### Message
Implementa uma mensagem customizada que o plugin vai utilizar para comunicação.
```
public class ChatMessage extends Message {
private String text;
private String name;
public ChatMessage(){
}
public ChatMessage(String name, String text){
this.name = name;
this.text = text;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the text
*/
public String getText() {
return text;
}
/**
* @param text the text to set
*/
public void setText(String text) {
this.text = text;
}
}
```
### Menus
Implementa os dois menus de Multicast utilizados pela aplicação.
#### ActionMenu
Esse menu apenas abre a janela principal do plugin.
```
public class ChatMulticastMenu extends MulticastActionMenu {
ChatWindow chatWindow;
public ChatMulticastMenu(ChatWindow chatWindow) {
this.chatWindow = chatWindow;
}
@Override
public String getText() {
return "Show Chat Window";
}
@Override
public void onClick() {
chatWindow.setVisible(true);
}
}
```
Esse menu abre a seção de menus do plugin Chat.
#### SubMenu
```
public class ChatMenu extends MulticastSubMenu {
ChatMulticastMenu chatMulticastMenu;
public ChatMenu(ChatWindow chatWindow) {
this.chatMulticastMenu = new ChatMulticastMenu(chatWindow);
}
@Override
public String getText() {
return "Chat";
}
@Override
public List<MulticastMenu> getMenus() {
return List.of(chatMulticastMenu);
}
}
```
### GUI
Essa é a janela principal do plugin de chat.
```
public class ChatWindow extends JDialog {
private JButton jButton1;
private JEditorPane jEditorPane1;
private JPanel jPanel1;
private JPanel jPanel2;
private JScrollPane jScrollPane1;
private JScrollPane jScrollPane2;
private JSplitPane jSplitPane1;
private JTextArea jTextArea1;
private final Pitiupi pitiupi;
public ChatWindow(Pitiupi pitiupi) {
this.pitiupi = pitiupi;
initComponents();
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
private void initComponents() {
this.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
this.setTitle("Chat Window");
this.setBounds(new java.awt.Rectangle(0, 0, 800, 600));
this.getContentPane().setLayout(new java.awt.BorderLayout(5, 5));
this.setPreferredSize(new java.awt.Dimension(800, 600));
jSplitPane1 = new JSplitPane();
jScrollPane1 = new JScrollPane();
jEditorPane1 = new JEditorPane();
jPanel1 = new JPanel();
jScrollPane2 = new JScrollPane();
jTextArea1 = new JTextArea();
jPanel2 = new JPanel();
jButton1 = new JButton();
jSplitPane1.setDividerLocation(500);
jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
jEditorPane1.setContentType("text/html");
jPanel1.setLayout(new java.awt.BorderLayout());
jTextArea1.setColumns(20);
jTextArea1.setRows(5);
jTextArea1.addKeyListener(new java.awt.event.KeyAdapter() {
@Override
public void keyTyped(java.awt.event.KeyEvent evt) {
if (evt.getKeyChar() == '\n') {
sendMessage();
}
}
});
jButton1.setText("Send");
jScrollPane1.setViewportView(jEditorPane1);
jScrollPane2.setViewportView(jTextArea1);
jSplitPane1.setTopComponent(jScrollPane1);
jPanel1.add(jScrollPane2, java.awt.BorderLayout.CENTER);
jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));
jButton1.addActionListener((java.awt.event.ActionEvent evt) -> {
sendMessage();
});
jPanel2.add(jButton1);
jPanel1.add(jPanel2, java.awt.BorderLayout.PAGE_END);
jSplitPane1.setRightComponent(jPanel1);
getContentPane().add(jSplitPane1, java.awt.BorderLayout.CENTER);
pack();
}
private void sendMessage() {
if (jTextArea1.getText().trim().isEmpty()) {
return;
}
ChatMessage message = new ChatMessage(pitiupi.getUserName(), jTextArea1.getText());
this.sendChatMessage(message);
jTextArea1.setText("");
}
public void sendChatMessage(Message message) {
pitiupi.sendUdpMulticast(message);
}
public void receiveChatMessage(ChatMessage message) {
SimpleDateFormat dt = new SimpleDateFormat("dd/MM/yyyyy hh:mm:ss");
Date date = new Date();
this.receiveChatMessage(dt.format(date) + " "
+ "<b>" + message.getName() + "</b>: "
+ message.getText() + "<br>");
}
public void receiveChatMessage(String message) {
jEditorPane1.setText(message + jEditorPane1.getText());
}
}
```
@@ -30,18 +30,6 @@ public class GuiManager {
}
public void createMenu(MenuCategory category, Menu menu) {
System.out.println(
menu.getClass().getSuperclass().getSuperclass()
);
System.out.println(
MulticastMenu.class
);
System.out.println(
menu.getClass().getSuperclass().getSuperclass()
== MulticastMenu.class
);
try {
JMenuItem newMenu = buildMenu(menu);
if (menu instanceof MulticastMenu) {
@@ -55,7 +43,6 @@ public class GuiManager {
logger.log(Level.WARNING, e.getMessage());
}
}
private JMenuItem buildMenu(Menu menu) {
if (menu instanceof MulticastSubMenu multicastSubMenu) {
JMenu newMenu = new JMenu(menu.getText());
@@ -1,5 +1,6 @@
package pitiupi.control.plugins;
import pitiupi.plugin.Pitiupi;
import pitiupi.Main;
import pitiupi.control.ConnectionManager;
import pitiupi.control.GuiManager;
@@ -92,6 +93,7 @@ public class PluginManager {
public void loadPlugins(ConnectionManager connectionManager, GuiManager guiManager) {
File pluginDir = new File("plugins");
File[] jarFiles = pluginDir.listFiles((dir, name) -> name.endsWith(".jar"));
Pitiupi pitiupi = new Pitiupi(connectionManager, guiManager);
if (jarFiles == null || jarFiles.length == 0) {
System.out.println("No plugins found in the " + pluginDir.getAbsolutePath() + " directory.");
@@ -118,7 +120,7 @@ public class PluginManager {
System.out.println("Loading: " + plugin.getName());
LoadedPlugin loadedPlugin = new LoadedPlugin(plugin, classLoader);
plugin.createPlugin(connectionManager, guiManager);
plugin.createPlugin(pitiupi);
loadedPlugins.add(loadedPlugin);
loadedJars.add(file.getName());
}
+4 -7
View File
@@ -3,9 +3,7 @@
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
*/
package pitiupi.models;
import pitiupi.control.ConnectionManager;
import pitiupi.control.GuiManager;
import pitiupi.plugin.Pitiupi;
import pitiupi.models.Messages.Message;
import pitiupi.net.tcp.TcpConnection;
@@ -30,10 +28,9 @@ public abstract class Plugin {
*
* <p>Este método é chamado pela aplicação após o carregamento do plugin.</p>
*
* @param connectionManager interface com o sistema de conexões da aplicação.
* @param guiManager interface com a janela principal da aplicação
* @param pitiupi interface com o sistema de conexões da aplicação.
*/
public abstract void createPlugin(ConnectionManager connectionManager, GuiManager guiManager);
public abstract void createPlugin(Pitiupi pitiupi);
/**
* Retorna uma mensagem utilizada pelo plugin.
@@ -62,4 +59,4 @@ public abstract class Plugin {
public boolean onSocketClosed(TcpConnection connection) {
return false;
}
}
}
+49
View File
@@ -0,0 +1,49 @@
package pitiupi.plugin;
import pitiupi.control.ConnectionManager;
import pitiupi.control.GuiManager;
import pitiupi.models.Menus.Menu;
import pitiupi.models.Menus.MenuCategory;
import pitiupi.models.Messages.Message;
import pitiupi.net.tcp.TcpConnection;
import java.net.InetAddress;
public class Pitiupi {
private final ConnectionManager connectionManager;
private final GuiManager guiManager;
public Pitiupi(ConnectionManager connectionManager, GuiManager guiManager) {
this.connectionManager = connectionManager;
this.guiManager = guiManager;
}
public boolean sendUdpMulticast(Message message) {
return connectionManager.sendUdpMulticast(message);
}
public boolean sendUdpUnicast(Message message, InetAddress address) {
return connectionManager.sendUdpUnicast(message, address);
}
public boolean sendTcp(Message message, InetAddress address) {
return connectionManager.sendTcp(message, address);
}
public TcpConnection connectTcp(InetAddress address, String senderId, String receiverId) {
return connectionManager.connectPluginTcp(address, senderId, receiverId);
}
public String getUserName() {
return connectionManager.getUserName();
}
public int getPort() {
return connectionManager.getPort();
}
public void createMenu(MenuCategory category, Menu menu) {
guiManager.createMenu(category, menu);
}
}