Is it possible to use RMI bidirectional between two classes?
Asked Answered
P

8

13

I want to share some information between two classes (A and B), which are running in different java programs. Instead of writing a whole communication protocol I want to use the java build-in rmi classes for that purpose. Currently class B is able to run a method which belongs to class A remotely. Is it somehow possible to use the same "connection" within class A to call a method of class B? Otherwise I probably have to implement a second rmi service ...

BR,

Markus

Prostitute answered 26/5, 2009 at 17:46 Comment(1)
An alternative to RMI would be the SIMON framework.Lewan
F
12

If B implements Remote, it can be export and passed as a parameter in an RMI call to A. In this scenario, there's no need to register B in an RMI registry, since the client is being passed a reference to it explicitly.

Falconet answered 26/5, 2009 at 18:16 Comment(7)
Mhhh, i think if I implement it that way there might occure some data inconsistencies between the "copied" and the "real" B, or?Prostitute
No, there is no "copy". When A calls a method on B, it's really invoking a remote method call via a stub to the "real" B. It's identical to B invoking a remote method on A, except that instead of looking up the object in a registry, A received the remote object as a parameter in a method call.Falconet
However, if I'm not mistaken, this won't work when B cannot accept incoming connections, e.g. when it is on a consumer network with NAT. Is there a way to do callbacks over the already existing connection?Zebe
@BartvanHeukelom In very early versions of RMI, traffic from the server to the client could be multiplexed over the original connection from client to server. But this feature was deprecated and removed in 1.2.2. With RMI, the "client" callback is in fact a service, and the "server" can only invoke the callback after opening a socket back to the "client."Falconet
@Falconet you mentioned "it can be exported". This means additional explicit code for exporting it, or there is some magic happening behind the scene ? If you have a good reference to read, please do share it. As a context: I am trying to implement the bidirectional communication in Spring env, but also trying to understand the process behindHuldahuldah
@Huldahuldah the export of a result that implements Remote is automatic, “magic happening behind the scenes.” I will try to find a reference.Falconet
@Falconet I have played a little more with the notions and did the magic! Anyway, thanks for the reply !Huldahuldah
P
7

I implemented 2 way RMI between cleint and server with server exposing its stub using Registry

  1. The client gets a stub of the server
  2. Then the client puts its stub as Observer to the server's addObserver method
  3. The server notifies the clients using this stub

The following code will gives a better idea

import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.util.Observable;
import java.util.Observer;
import java.net.*;

import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;

interface ReceiveMessageInterface extends Remote
{
    /**
     * @param x
     * @throws RemoteException
     */
    void receiveMessage(String x) throws RemoteException;

    /**
     * @param observer
     * @throws RemoteException
     */
    void addObserver(Remote observer) throws RemoteException;
}

/**
 * 
 */
class RmiClient extends UnicastRemoteObject
{
    /**
     * @param args
     */
    static public void main(String args[])
    {
        ReceiveMessageInterface rmiServer;
        Registry registry;
        String serverAddress = args[0];
        String serverPort = args[1];
        String text = args[2];
        System.out.println("sending " + text + " to " + serverAddress + ":" + serverPort);
        try
        { // Get the server's stub
            registry = LocateRegistry.getRegistry(serverAddress, (new Integer(serverPort)).intValue());
            rmiServer = (ReceiveMessageInterface) (registry.lookup("rmiServer"));

            // RMI client will give a stub of itself to the server
            Remote aRemoteObj = (Remote) UnicastRemoteObject.exportObject(new RmiClient(), 0);
            rmiServer.addObserver(aRemoteObj);

            // call the remote method
            rmiServer.receiveMessage(text);
            // update method will be notified
        }
        catch (RemoteException e)
        {
            e.printStackTrace();
        }
        catch (NotBoundException e)
        {
            System.err.println(e);
        }
    }

    public void update(String a) throws RemoteException
    {
        // update should take some serializable object as param NOT Observable
        // and Object
        // Server callsbacks here
    }
}

/**
 * 
 */
class RmiServer extends Observable implements ReceiveMessageInterface
{
    String address;
    Registry registry;

    /**
     * {@inheritDoc}
     */
    public void receiveMessage(String x) throws RemoteException
    {
        System.out.println(x);
        setChanged();
        notifyObservers(x + "invoked me");
    }

    /**
     * {@inheritDoc}
     */
    public void addObserver(final Remote observer) throws RemoteException
    {
        // This is where you plug in client's stub
        super.addObserver(new Observer()
        {
            @Override
            public void update(Observable o,
                Object arg)
            {
                try
                {
                    ((RmiClient) observer).update((String) arg);
                }
                catch (RemoteException e)
                {

                }
            }
        });
    }

    /**
     * @throws RemoteException
     */
    public RmiServer() throws RemoteException
    {
        try
        {
            address = (InetAddress.getLocalHost()).toString();
        }
        catch (Exception e)
        {
            System.out.println("can't get inet address.");
        }
        int port = 3232;
        System.out.println("this address=" + address + ",port=" + port);
        try
        {
            registry = LocateRegistry.createRegistry(port);
            registry.rebind("rmiServer", this);
        }
        catch (RemoteException e)
        {
            System.out.println("remote exception" + e);
        }
    }

    /**
     * 
     * @param args
     */
    static public void main(String args[])
    {
        try
        {
            RmiServer server = new RmiServer();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.exit(1);
        }
    }
}
Penalty answered 5/10, 2012 at 11:8 Comment(0)
E
1

It's been a while since I've used RMI, but IIRC if class B implements java.rmi.Remote and passes a reference to an instance of itself as a parameter to the method in class A, then class A should receive a stub and methods called on it will be called on the original instance.

However, if you have a lot of such RMI calls going back anf fro, you will probably encounter performance problems.

Emmyemmye answered 26/5, 2009 at 17:55 Comment(0)
M
1

If you pass B as an argument to a method in A and then use that reference to call a method on B I am fairly certain that a reverse connection is established, and I am fairly certain that RMI Registry is created for the JVM where B resides. At some point this got us into a bit of trouble with particularly strict firewall rules. Our code looked a little something like

Web Server

public int uploadFile(FileItem fileItem){
    return ApplicationClassLoader
        .get(DocumentManager.class)
        .attachFile(new RemoteInputStreamImpl(fileItem.getInputStream());
    )
}

Application Server

public int attachFile(RemoteInputStream in){
    ...

    byte[] buffer;
    while((buffer = in.read(1024)) != null) // Would return null to indicate EOF
      // Do some stuff

    return documentId;       
}
Manhour answered 26/5, 2009 at 21:11 Comment(0)
D
-1

Both JVMs would need to implement RMI services. But that is really very easy look at the various classes in java.rmi.

What you can't do is somehow use one RMI connection and do two way communication.

Decosta answered 26/5, 2009 at 18:9 Comment(0)
K
-1

Some RMI service support callbacks or listeners which allow the server to asynchronous call the client down the same connection. (Sorry I don't remember the name of the open libraries which do this, a quick google wasn't very helpful) Standard RMI doesn't support this, instead you need to expose the client as an RMI service as well.

Keaton answered 26/5, 2009 at 22:4 Comment(0)
P
-1

RMI bidirectional:

SERVER:

import java.io.IOException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class RMISERVER {

   public RMISERVER() throws IOException {

       Thread t;
        try {
            t = new Prou_run();
            t.start();
        } catch (RemoteException ex) {
            Logger.getLogger(RMISERVER.class.getName()).log(Level.SEVERE, null, ex);
        }

   }


   public static void main(String args[]) throws IOException {
     new RMISERVER();
   }
}


import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.tree.DefaultMutableTreeNode;

//extends java.rmi.server.UnicastRemoteObject
public class Prou_run extends Thread implements Runnable{

            New_Object  root = null,root2=null,root3=null,root4=null,root5;
              New_Object new_root=null;
            Object xt = null, xt2=null , xt3=null;
            Registry r1,r2;
            RMIClientSocketFactory csf,csf2;
            RMIServerSocketFactory ssf,sf2;


            new_Patryk npal;

 public Prou_run() throws java.rmi.RemoteException, IOException
 {
         if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
                  }

//            csf = new RMIClientSocketFactory() {
//
//                public Socket createSocket(String host, int port) throws IOException {
//                    return new Socket("rmi://localhost/getchil",1080);
//                }
//            };
//            csf2 = new RMIClientSocketFactory() {
//
//                public Socket createSocket(String host, int port) throws IOException {
//                   return new Socket("rmi://localhost/getchild",1081);
//                }
//            };
//            ssf=new RMIServerSocketFactory() {
//
//                public ServerSocket createServerSocket(int port) throws IOException {
//                    return new ServerSocket(1099);
//                }
//            };// ssf.createServerSocket(1099);
//              sf2=new RMIServerSocketFactory() {
//
//                public ServerSocket createServerSocket(int port) throws IOException {
//                   return new ServerSocket(1098);
//                }
//            };//sf2.createServerSocket(1098);
       try {
         r1=java.rmi.registry.LocateRegistry.createRegistry(1098);
                 r2=java.rmi.registry.LocateRegistry.createRegistry(1099);//, csf2, ssf);
                 java.rmi.registry.LocateRegistry.createRegistry(1097);
                 java.rmi.registry.LocateRegistry.createRegistry(1095);
                 java.rmi.registry.LocateRegistry.createRegistry(1096);
         System.out.println("RMI registry ready.");
      } catch (Exception e) {
         System.out.println("Exception starting RMI registry:");
         e.printStackTrace();
      }
        this.xt = null;this.xt2 = null;this.xt3 = null;
        npal = new new_Patryk();
        System.out.println("sdmmmfxxxxxxxx");

   }






    public void run() {

//while(true){

      try{

//             root =  new_root;
//             xt=npal.getChild((File)new_root.getob(), (int)new_root.geti());
             New_ObjectIMPL sl = new New_ObjectIMPL();
             sl.i=354;
                System.out.println("sdmmmf2");
                //r2
             Naming.rebind("rmi://localhost:1099/getchild",(New_Object) sl);
                System.out.println("sdmmmf3");

         }catch (Exception e) {
       System.out.println("Trouble: " + e);
     }

        while(new_root==null){
            try{
                 //System.out.println("sdmmmf1"   +   new_root.geti());
         new_root = (New_Object) Naming.lookup("rmi://localhost:1080/getchil");
         System.out.println("sdmmmf1"   +   new_root.geti());
            }catch (Exception e) {
       System.out.println("Trouble: " + e);
     }
        }
    }

}

























/**
 *
 * @author austinchuma
 */
public interface New_Object extends java.rmi.Remote {

     public int geti() throws java.rmi.RemoteException;

     public Object getob() throws java.rmi.RemoteException;

     public Object getobchild() throws java.rmi.RemoteException;

      public boolean getbbol() throws java.rmi.RemoteException;

       public byte[] getb() throws java.rmi.RemoteException;



}





public class New_ObjectIMPL extends java.rmi.server.UnicastRemoteObject implements New_Object

{
   Object ob = null,obchild = null;
    int  i=0;
    boolean bol = false;
    byte[] b = null;

    public New_ObjectIMPL() throws RemoteException{
        ob = null;obchild = null;
        i=0;
        bol = false;
        b = null;
    }

    public int geti() throws RemoteException {
       return i;
           }

    public Object getob() throws RemoteException {

       return ob;
    }

    public Object getobchild() throws RemoteException {
       return obchild;
    }

    public boolean getbbol() throws RemoteException {
      return bol;
    }

    public byte[] getb() throws RemoteException {

        return b;

    }


}
Photochromy answered 24/7, 2010 at 10:52 Comment(0)
E
-2

How would class B know about class A without a second RMI server though? I think you are going to need two servers.

Epochmaking answered 26/5, 2009 at 17:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.