Integrantes:
- Ricardo Itiro Sabota Tominaga
- Marcus Leandro
Ano/sem: 2008/2o.
Introdução
O projeto consistiu no desenvolvimento de um software similar ao famoso "MSN messenger" utilizando-se, para isso, a linguagem Java. A semelhança com o "MSN messenger" se dá devido ao aspecto estético e de utilização. No entanto, o funcionamento é diferente, uma vez que, cada usuário corresponde a um cliente e um servidor simultâneamente. Assim, pode-se requisitar ou receber requisição de conexão com o mesmo programa. Deve-se salientar que não há servidor intermediário que administra as conexões, ou seja, gera-se uma conexão ponto-a-ponto.
O programa e o seu manual de instruções pode ser obtido em [http://code.google.com/p/chatlan/]
[http://code.google.com/p/chatlan/downloads/list].
Funcionamento
Nesta seção será detalhado o funcionamento do programa em termos de código fonte (classes e objetos) e execução (telas).
Classes e objetos
As classes presentes são:
- ChatConnection
- ChatWindow
- ChatWindowBuilder
- ClasseExecucao
- ConnectionWindow
- GenericClient
- GenericServer
- P2PConnection
ClasseExecucao
Responsável por criar o servidor (entenda-se a "thread" do servidor") e a janela de conexão.
new GenericServer(5000); new ConnectionWindow();
ConnectionWindow
Cria uma tela de conexão (JFrame) com um textfield e um botão. A função do botão é instanciar um cliente.
public class ConectorActionListener implements ActionListener{ public void actionPerformed(ActionEvent e) { new GenericClient(field.getText(), 5000); } }
GenericClient
Cria uma conexão (socket) e instancia um objeto ChatConnection.
public GenericClient(String host,int port){ try{ clientSocket = new Socket(host,port); }catch(Exception e){e.printStackTrace();} new ChatConnection(clientSocket); }
ChatConnection e P2PConnection
ChatConnection é subclasse da classe abstrata P2PConnection e implementa o método abstrato useConnection instanciando uma ChatWindow. A classe abstrata P2PConnection cria os canais de entrada e saída (BufferedReader/PrintWriter) responsáveis por receber e enviar informações.
entrada = new BufferedReader(new InputStreamReader(con.getInputStream())); saida = new PrintWriter(con.getOutputStream());
ChatWindow
Recebe como parâmetros os canais de entrada e saída e os IPs local e remoto. Cria o frame de chat com o ChatWindowBuilder e seta esse frame como "visible".
ChatWindowBuilder chatBuilder = new ChatWindowBuilder("Messenger Maroto", entrada, saida, localIp, hostIp); chatBuilder.CreateAll(); frame = chatBuilder.getFrame(); frame.setVisible(true);
ChatWindowBuilder
Builder do frame da tela de chat. Instancia um frame, três panels, um botão e dois textareas com barra de rolagem e os monta ao frame final. Possui um método que realiza toda a montagem.
public void CreateAll(){ CreateIncomingTextArea(); CreateOutgoingTextArea(); CreateSendButton(); BuildFrame(); }
GenericServer
Cria uma thread que "ouve" requisições de conexão. Quando recebe uma requisição, cria uma conexão e instancia uma ChatConnection.
public class EsperaConexao implements Runnable{ public void run() { try{ while(true){ Socket client = serverSocket.accept(); new ChatConnection(client); } }catch(Exception e){e.printStackTrace();} } }
Telas
Em seguida, são mostradas as telas do programa.
Tela de Conexão

Fig.1 Tela de conexão
Na tela de conexão há um textfield no qual é inserido o IP do usuário a quem se quer conectar. Logo em seguida, clica-se no botão para cria a nova conexão. Pode-se conectar com vários usuários ao mesmo tempo, sendo que cada nova conexão corresponde a uma nova tela de conversação.
Tela de Chat

Fig.2 Tela de Conversação
Na tela de conversação há dois textareas, um para envio de texto e outro para recebimento. No de recebimento, aparacem tanto as informações recebidas como as enviadas. Para se enviar texto clica-se no botão de envio.
Padrões de projeto utilizados
Os padrões de projeto utilizados foram o Template e o Builder.
Template
O padrão template foi utilizado na classe P2PConnection, uma vez que ela permite a criação de diversas utilizações para os canais de comunicação através da implementação do método abstrato useConection. No caso, foi criada apenas a subclasse ChatConnection, mas poder-se-ia utilizar a classe P2PConnection para criar um servidor que registra os usuários ativos e os repassa para os outros, de forma que todos os usuários teriam ciência daqueles que estão ativos.
public abstract class P2PConnection { (...) public P2PConnection(Socket con){ (...) useConnection(); } public abstract void useConnection(); }
Builder
O padrão builder foi utilizado na criação da tela de conversação, uma vez que ela é um objeto complexo. Nesse caso, o padrão serviu para melhorar a visibilidade na criação da tela, uma vez que, há muito código envolvido.
public class ChatWindowBuilder { (...) public ChatWindowBuilder(...) { (...) } public void CreateIncomingTextArea(){ (...) } public void CreateOutgoingTextArea(){ (...) } public void CreateSendButton(){ (...) } public void BuildFrame(){ (...) } public void CreateAll(){ (...) } public JFrame getFrame(){ return frame; } (...) }
Diagrama de Classes
Abaixo segue o diagram UML para que se possa visualizar as classes do projeto e ver como elas se relacionam.
Diagrama UML

Fig.3 Diagrama UML
Funções extras
Para melhorar o funcionamento do projeto, implementamos algumas funções extras com o intuito de melhorar a vida do utilitário.
A primeira delas é o envio da mensagem apertanto a tecla enter através do JTextArea, cabe salientar que só apertar enter faz com que enviemos um mensagem já escrita, mas quando se aperta shift+enter pulamos de linha no JTextArea destinado a enviar as mensagens, assim como é no msn.
Para implementar tal ttarefa tive que adionar ao JTextArea um KeyListener e em seguida implementar uma classe interna que extendesse KeyListner chamada EnterListener cujo código colocarei encontra-se abaixo.
public class EnterListener implements KeyListener{ private boolean auxiliar = false; // me auxiliará pra eu detectar o shift+enter no TextArea public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_SHIFT){ auxiliar = true; } } public void keyTyped(KeyEvent e) {} public void keyReleased(KeyEvent e) { if (auxiliar == false && (e.getKeyCode() == KeyEvent.VK_ENTER) ){ String[] semEnter = outgoing.getText().split("\\n"); for(String s:semEnter){ saida.println(s); saida.flush(); String[] str = localIp.split("/"); incoming.append(str[1]+" (me): " + s + "\n"); } outgoing.setText(""); outgoing.requestFocus(); } else if(e.getKeyCode() == KeyEvent.VK_SHIFT){ auxiliar = false; } else if(auxiliar == true && (e.getKeyCode() == KeyEvent.VK_ENTER) ){ outgoing.append("\n"); } } }
Para eu detectar a diferença do shift+enter e do enter puro eu utilizei uma variável de instancia para me auxiliar, setando ela inicialmente como falso (private boolean auxiliar = false), toda vez e enquanto o shift está sendo precionado essa variável recebe o valor de true, assim, sei qd eu tenho um enter sem ter um shift junto e quando eu tenho um enter com um shift junto, basta eu verificar essa variável.
Cabe salientar que o motivo dessa calsse ser uma classe interna se deve ao fato de eu querer utilizar as variável da classe externa a ela, caso contrário teria que ficar passando variáveis ao construtor dessa classe, o que aumentaria o aclopamento e tornando assim menos eficiente o código.
Como segunda implementação extra foi adicionar som. toda vez que o uma das pessaos na conversa fechar a janela, quando a outra lhe mandar uma mensagem, reabriremos a janela anterior, minimizaremos essa janela e tocará um som para despertar a atenção dessa pessoa que tinha fechado sua janela. Para me auxiliar nesse processo utilizei a classe Player de javazoom.jl.payer.Player, cujo download se encontra no link [http://www.javazoom.net/javalayer/javalayer.html]
a implementação dessa funcionalidade se encontra abaixo:
public class IncomingReader implements Runnable{ public void run() { String mensagem; try{ while( (mensagem = entrada.readLine()) != null ){ if(!frame.isShowing() || frame.getExtendedState() == JFrame.ICONIFIED ){ // se o usuário fechar a janela ou ela estive minimizada, ao se enviar frame.setExtendedState( JFrame.ICONIFIED ); // evitar que a janela a ser aberta sobreponha as outras. try{// também tocara uma musiquinha. File file = new File("sons\\type.mp3"); InputStream in = (InputStream) (new FileInputStream(file)); Player plr = new Player(in); plr.play(); frame.setVisible(true); }catch(Exception e){e.printStackTrace();} } System.out.println("ler " + mensagem); String[] str = hostIp.split("/"); incoming.append(str[1]+" (your friend): " + mensagem + "\n"); } }catch(Exception e){e.printStackTrace();} } } }
A classe em que se encontra tal parte de código é a IncomingReader que extend Runnable e é classe interna de ChatWindow, a razão dela ser classe interna é a mesma da explica anteriormente.
Por fim, não posso nem dizer que isso seja uma funcionalidade extra, mas comentarei que foi adionado uma imagem para substituir o simbolo da java que fica no canto superior esquerdo de toda frame, coloquei a imegem simbolo do msn e para tal utilizei o seguinte comando: frame.setIconImage(imagem);
Conclusão
Enfim, como podemos ver, temos uma aplicação que utiliza conexão ponto a ponto e o envio de informações através dela, que no nosso caso são linhas de texto.
De todas as tarefas realizadas, tanto na minha opinião como na do meu parceiro, essa foi a que mais nos engrandeceu nesse curso. Nos viramos muito sozinhos para aprender inúmeras coisas. Pra se ter idéia, para que implementasse a parte do envio da mensagem através de enter e pular linha com shift+enter, foi uma pesquisa realizada que demorou em torno de 3 horas, mas foi proveitoso no que se diz reipeito ao aprendizado, pois não só aprendi como aprendi a aprender sozinho.
Também pode-se salientar, que com essa aplicação, pudemos utilizar do que foi aprendido no curso de ces-22 e observamos que apesar de meses de estudo aquilo ainda não era suficiente para realizar um projeto maior.
Observamos a grande utilidade de se saber padrões de projetos, conhecendo-os podemos conjecturar códigos mais bem estruturados e "limpos", sem "gambiarras" e mais legíveis. Pode-se dizer inclusive, que o conhecimento de alguns deles, nos faz ter soluções para implementações que sem eles possivelmente não saberiamos como fazer.
Enfim, padrões de projetos são conceitos de implementações para determinadas situações, que nos facilitam para determinados problemas específicos aos quais cada um deles se encaixam.
Estatísticas
- 8 arq ".java"
- 302 linhas de código
- 60 linhas em branco





