comunicação entre objetos remotos com RMI - duvida cruel!

Oi,

(Darei um contexto rapido pra que a duvida possa ser bem explanada.)

No meu sistema que estou desenvolvendo, há um programa central e um conjunto de whiteboards distribuidos entre máquinas diversas (não se incomode se não souber o que é um whiteboard…). No sistema, o desenho feito (um serializable objeto, em verdade) sobre um desses whiteboards deve ser feito também em todos os outros. Como? o programa central recebe sempre a imagem gerada por um whiteboard e então repassa tal imagem para os outros whiteboards. Então, cada whiteboard funciona como cliente, já que acessa um (ou mais) método remoto do programa central (pelo qual transmite a imagem), e é também servidor pois é acessado remotamente pelo programa central (quando uma imagem de outro whiteboard está sendo distribuída…). Já com relação ao programa central, ele é servidor em relação aos whiteboards, e é algo como um “cliente universal”, pois precisa poder acessar todos os whiteboards. Entenderam?
O caso é que o programa central só consegue acessar os métodos remotos dos objetos contidos no rmiregistry local… é justamente isso o meu problema - cada whiteboard estará hospedado em uma máquina diferente!

hm… nesse seu caso, não seria o caso de deixar apenas 1 whiteboard no servidor mesmo, e todos os outros desenharem diretamente nele?

acho que isso daria certo… talvez até tente alguma coisa aqui, fiquei curioso hehehe

[quote=dudaskank]hm… nesse seu caso, não seria o caso de deixar apenas 1 whiteboard no servidor mesmo, e todos os outros desenharem diretamente nele?

acho que isso daria certo… talvez até tente alguma coisa aqui, fiquei curioso hehehe
[/quote]
Olá,

talvez voce nao tenha entendido direito :roll: . Veja: o caso é que os whiteboards tanto “desenham” o programa servidor (lhe enviam imagens por metodos remotos), como são desenhados por ele (o whiteboard1 recebe toda e qq imagem desenhada pelos demais whiteboards. Como? isso é feito atraves do programa central, que se encarrega de fazer tal distribuicao). Deu pra entender? Toda imagem gerada num wb é passada pro programa central, que tem a funcao exclusiva de repassar cada objeto (imagem) recebido pra todos os whiteboards (exceto o que enviou, dependendo da logica adotada…).

Oi Icaro,
Você poderia fazer os objetos remotos se registrarem em uma locação única, chamando Naming.rebind nos clientes para que eles se registrassem no servidor central.
Mas de qualquer maneira acho isso low level demais.
Se eu fosse você eu usaria o JGroups para manter essas estruturas de dados distribuidas, de saída você se livra da complicação de RMI, de registry e trabalha com uma API com um nível de abstração mais alto.

[quote=eliziario]Oi Icaro,
Você poderia fazer os objetos remotos se registrarem em uma locação única, chamando Naming.rebind nos clientes para que eles se registrassem no servidor central.[/quote]
Olá.

Foi justamente dessa forma que eu tinha projetado o sistema! Mas dai vem um probleminha/questao: os objetos podem ser registrados em um rmiregistry de uma outra máquina, que não seja a local em que estão rodando? Hoje, isso já não me parece possivel… :frowning:
Se há como fazer isso me diga como se faz pelamor de Deus!!!

[quote=eliziario]
Mas de qualquer maneira acho isso low level demais.
Se eu fosse você eu usaria o JGroups para manter essas estruturas de dados distribuidas, de saída você se livra da complicação de RMI, de registry e trabalha com uma API com um nível de abstração mais alto.[/quote]
Bom, caso com RMI não me venha a solução, vou procurar por outras alternativas. Valeu pelo toque dessa.

Realmente com o rmiregistry padrão nâo dá, porque ele não deixa você fazer o bind por outra máquina.
Mas você pode fazer seu próprio registry. Estou te mandando um exemplo, bem cru, de uma implementação de um Registry. Não tem segurança nem nada e não aceita parametrizações, mas é o básico para funcionar, é só botar pra rodar ao invés do rmiregistry.


import sun.rmi.transport.LiveRef;
import sun.rmi.server.UnicastServerRef;
import sun.rmi.server.LoaderHandler;
import sun.misc.URLClassPath;

import java.rmi.registry.Registry;
import java.rmi.*;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteServer;
import java.util.Hashtable;
import java.util.Map;
import java.net.URLClassLoader;

/**
 * Created by IntelliJ IDEA.
 * User: msantos
 * Date: 15/04/2006
 * Time: 22:39:34
 */
public class CustomRegistry extends RemoteServer implements Registry {
    private Map<String,Remote> bindings;
    private static CustomRegistry registry;
    private static ObjID id = new ObjID(0);


    public static void main(String[] args) throws RemoteException {
        String s = System.getProperty("env.class.path");
        if(s == null)
            s = ".";
        java.net.URL url[] = URLClassPath.pathToURLs(s);
        URLClassLoader urlClassLoader = new URLClassLoader(url);
        LoaderHandler.registerCodebaseLoader(urlClassLoader);
        Thread.currentThread().setContextClassLoader(urlClassLoader);
        int i = 1099;
        registry = new CustomRegistry(i);
        do
            try {
                Thread.sleep(100000000);
            }
            catch(InterruptedException interruptedexception) { }
        while(true);

    }

    public CustomRegistry(int port) throws RemoteException {
        bindings = new Hashtable<String, Remote>();
        LiveRef liveRef = new LiveRef(id, port);
        init(new UnicastServerRef(liveRef));

    }
    private void init(UnicastServerRef serverRef) throws RemoteException {
        ref = serverRef;
        serverRef.exportObject(this, "Server", true);
    }

    public Remote lookup(String name) throws RemoteException, NotBoundException, AccessException {
        synchronized(bindings) {
            Remote remote = bindings.get(name);
            if (remote == null) {
                throw new NotBoundException(name);
            }
            return remote;
        }
    }

    public void bind(String name, Remote obj) throws RemoteException, AlreadyBoundException, AccessException {
        synchronized(bindings) {
            Remote remote = bindings.get(name);
            if(remote != null) {
                throw new AlreadyBoundException(name);
            }
            bindings.put(name, obj);
        }
    }

    public void unbind(String name) throws RemoteException, NotBoundException, AccessException {
        synchronized(bindings) {
            Remote remote = bindings.get(name);
            if(remote != null) {
                throw new NotBoundException(name);
            }
            bindings.remove(name);
        }
    }

    public void rebind(String name, Remote obj) throws RemoteException, AccessException {
        synchronized(bindings) {
            bindings.put(name, obj);
        }

    }

    public String[] list() throws RemoteException, AccessException {
        return bindings.keySet().toArray(new String[bindings.keySet().size()]);
    }
}

Um exemplo de utilização:


import javax.naming.NamingException;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.server.RemoteStub;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

/**
 * Created by IntelliJ IDEA.
 * User: msantos
 * Date: 15/04/2006
 * Time: 19:43:58
 */
public class RmiTest implements Remote, Exported {
    public static void main(String[] args) throws NamingException, RemoteException, AlreadyBoundException, NotBoundException {

        Registry server = (Registry) LocateRegistry.getRegistry("nyc-laptop2");
        System.out.println("Env is" + server);

        RmiTest rmitest = new RmiTest();
        RemoteStub reg = UnicastRemoteObject.exportObject(rmitest);
        server.bind("teste", reg );

        String[] lista = server.list();
        for (String val: lista) {
            System.out.println("Element ->" + val);
        }
        Exported remote = (Exported) server.lookup("teste");
        System.out.println("Remote object says: " + remote.hello());
        System.exit(0);
    }

    /**
     * From remote interface
     */
    public String hello() throws RemoteException {
        return "Hello";
    }
}
import java.rmi.Remote;
import java.rmi.RemoteException;

/**
 * Created by IntelliJ IDEA.
 * User: msantos
 * Date: 15/04/2006
 * Time: 19:49:52
 */
public interface Exported extends Remote {
    public String hello() throws RemoteException;

}

abs,
Marcos

1 - Seria impraticável se cada whiteboard acessasse o servidor central em intervalos de tempo regulares para fazer o download das imagens???

2 - Ou então se cada whiteboard tivesse o seu próprio rmiregistry e a cada inicialização, eles se registrassem ao servidor central, com isso vc armazena no servidor central os ips dos whiteboards ativos.

3 - Ou se vc desse um nome difirente para cada whiteboard no rmiregistry. Tipo: whiteboard_1, whiteboard_2 ou whiteboard_192.168.45.10, whiteboard_192.168.45.11 e assim por diante…

Eu já trabalhei num projeto de IC que fazia algo parecido com isso que voce quer e nós adotamos a 3 opção.

[quote=ax]1 - Seria impraticável se cada whiteboard acessasse o servidor central em intervalos de tempo regulares para fazer o download das imagens???

2 - Ou então se cada whiteboard tivesse o seu próprio rmiregistry e a cada inicialização, eles se registrassem ao servidor central, com isso vc armazena no servidor central os ips dos whiteboards ativos.

3 - Ou se vc desse um nome difirente para cada whiteboard no rmiregistry. Tipo: whiteboard_1, whiteboard_2 ou whiteboard_192.168.45.10, whiteboard_192.168.45.11 e assim por diante…

Eu já trabalhei num projeto de IC que fazia algo parecido com isso que voce quer e nós adotamos a 3 opção.[/quote]
olá,

1-podia ser, e talvez fosse menos custoso até pras conexões, nao sei, mas os WBs não seriam tão “fieis” entre si, justamente pela demora nas atualizações. Além disso, seria preciso uma ferramenta extra - pra armazenar, daquelas nova imagens feitas, as que ainda nao foram ainda distribuidas pra serem…
2-acho que isso seria mais complicado que com um unico rmiregistry, da forma que eu havia indicado: do modo como eu tinha dito, ficaria facil enviar as imagens aos Wbs todos porque o rmiregistry já conteria as referencias diretas a todos eles, saca? Entao, caso um wb fosse fechado, por ex, seria mais facil atualizar isso no servidor, eu acho. Mas eu ainda vou pensar mais sobre a ideia…
3-a 3a realmente parece pra mim ser a mais simples, e foi justamente a que eu tive pra fazer no projeto (também de IC). Funciona de forma que cada wb se registra num mesmo lugar, com nomes distintos entre si, e este lugar era o responsavel por receber e redistribuir imagens dos wbs registrados.

valeu ai pelas ideias. vou estuda-las melhor aqui, embora eu ainda esteja por fazer o esquema do rmiregistry customizado como o eliziario indicou…

[quote=eliziario]Realmente com o rmiregistry padrão nâo dá, porque ele não deixa você fazer o bind por outra máquina.
Mas você pode fazer seu próprio registry. Estou te mandando um exemplo, bem cru, de uma implementação de um Registry. Não tem segurança nem nada e não aceita parametrizações, mas é o básico para funcionar, é só botar pra rodar ao invés do rmiregistry.
.
.
.
.
[/quote]
olá.

Já montei aqui o esquema que tu indicou com o rmiregistry customizado, mas só tem um probleminha pra funcionar ainda (eu acho):

eu estava usando, pra obter as referencias aos objetos remotos registrados e também pra registrar, um Context (eu instanciava InitialContext), que por sua vez tinha um método que para o meu caso é essencial - listBindings - por meio do qual eu poderia obter as referencias aos WBs registrados e daí enviar-lhes as imagens… (entre outras coisas, por métodos remotos dos WBs). Porém, na tua implementação do rmiregistry eu obtenho, pra fazer os lookup’s e bind’s, um Registry, que não tem esse método que preciso… Então, teria como adaptar a implementação pra obter referencia aos objetos registrados (por ex., obter uma referencia a Map bindings)???