RMI - Mini Chat

Bem, já fiz chat usando Socket e agora foi a vez do RMI.
No RMI percebi a facilidade pra chamar métodos remotos, porém vi a dificuldade para fazer um chat multi client.
Ví vários exemplos na internet e vi vários aqui no GUJ, mas nenhum foi como eu imaginei, dai fiz a seguinte GAMBIARRA.
Nos exemplos, o cliente se conecta ao Servidor e envia uma mensagem, no máximo, o servidor imprime essa mensagem, já que não se tem caminho de volta sem que o Cliente fique esperando um retorno. Dai o que acontece se o servidor informar algo que o cliente não está esperando? Nada, o cliente nem sabe que tem que pegar alguma coisa no servidor.
Então pensei, o servidor recebe comandos sem esperar, então o cliente pode ser um servidor também e receber comandos do servidor sem esperar.
Dai fiz o seguinte algoritmo.

Client.java

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import javax.swing.JOptionPane;

@SuppressWarnings("serial")
public class Client extends UnicastRemoteObject implements CRClient {
	public Client() throws RemoteException {super();} 
	
	public static void main(String[] args) {
		CRServer conn;
		try {
			conn = (CRServer) Naming.lookup("//127.0.0.1/Server1");
			try {
				String login = JOptionPane.showInputDialog(null, "Poe seu nick ai");
				Naming.rebind(login, new Client());
				Player player = new Player();
				player.setLogin(login);
				conn.connect(player);
				conn.sendMessage(player, JOptionPane.showInputDialog(null, "Digite uma mensagem"));
				conn.disconnect(player);
			} catch (Exception e) {
				System.out.println("Erro: " + e.getMessage());
				e.printStackTrace();
			}
		} catch (Exception e) {
			System.out.println("Client exception: " + e.getMessage());
			e.printStackTrace();
		}
	}

	@Override
	public void receiveMessage(String msg) throws RemoteException {
		System.out.println(msg);
	}
}

CRClient.java

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface CRClient extends Remote {
	void receiveMessage(String string) throws RemoteException;
}

CRServer.java

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface CRServer extends Remote {
	void connect(Player player) throws RemoteException;
	void sendMessage(Player player, String msg) throws RemoteException;
	void disconnect(Player player) throws RemoteException;
}

Player.java

import java.io.Serializable;

@SuppressWarnings("serial")
public class Player implements Serializable {
	private String nome;
	private String login;
	
	private CRClient lookup;

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String getNome() {
		return nome;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getLogin() {
		return login;
	}

	public void setConn(CRClient lookup) {
		this.lookup = lookup;
	}

	public CRClient getConn() {
		return lookup;
	}
}

Server.java

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;

@SuppressWarnings("serial")
public class Server extends UnicastRemoteObject implements CRServer {
	private ArrayList<Player> players = new ArrayList<Player>();
	
	public Server() throws RemoteException {super();} 

	public static void main(String args[]) {
		try {
			Naming.rebind("Server1", new Server());
			System.out.println("Servidor Iniciado");
		} catch (Exception e) {
			System.out.println("Erro: " + e.getMessage());
			e.printStackTrace();
		}
	}

	@Override
	public void sendMessage(Player player, String msg) throws RemoteException {
		for(Player playerX : players) {
			playerX.getConn().receiveMessage(player.getLogin() + " diz: " + msg);
		}
	}
	
	@Override
	public void connect(Player player) throws RemoteException {
		players.add(player);
		try {
			player.setConn((CRClient) Naming.lookup("//127.0.0.1/" + player.getLogin()));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (NotBoundException e) {
			e.printStackTrace();
		}
		System.out.println("Player conectou: " + player.getLogin());
	}

	@Override
	public void disconnect(Player player) throws RemoteException {
		players.remove(player);
		System.out.println("Player desconectou: " + player.getLogin());
	}
}

Se analisarem, vão ver que o Client.java se conecta a Server.java e pede um login ao usuario, após inserir e dar ok, o Client.java abre um servidor e diz pro Server.java que ele agora é um servidor e pode também receber pedidos do servidor.

Foi a única maneira que vi de trocar mensagem como no socket.

Alguem costuma fazer diferente? Ou fiz certo? Ou fiz gambiarra das brabas? hehehe

[Comandos para utilizar]
javac *.java
rmic Server
rmic Client
start rmiregistry
start java Server
start java Client

1 curtida

Bom, fiz então o seguinte, depois que o cliente se conecta ao servidor, ele vira um servidor para o servidor. Dai ambos conseguem trocar mensagem de maneira fácil.
Só não sei se fiz errado, se fiz certo, se tem outra maneira de fazer e etc.

Tem alguma outra maneira do cliente ficar recebendo comandos enviados pelo servidor sem ter que fazer essa gambiarra?

Pensei em fazer uma thread que verifica se tem novas mensagens no servidor.