Passing object reference using RMI
Asked Answered
S

2

3

Hello everyone,

I have been banging my head really hard trying to solve this problem. I really appreciate if anyone can please have a look at my problem and help me.

I have multiple clients that uses Java RMI to establish a connection (register()) and receive a list of connects clients from the server (get()). My goal is to get clients to talk to each other using RMI, without having to register themselves, only the server so far is being register.

I am trying to pass a reference of the client object to the server.

I am getting the following error:

java.rmi.MarshalException: error marshalling arguments; nested exception is: 
    java.io.NotSerializableException: Client

I do not want to use Serialization (I believe), as I don't want to pass the object itself, but a reference. Client1 should be able to send a message to Client2 by calling client2.messsage(String username, String message);

I believe I should just show you at this point how I have implemented my code:

public interface RMIClientIntf extends Remote {
    public void message(String name, String message) throws RemoteException;
    public String getName() throws RemoteException;
}

The previous code is what all clients should implement. If the message() function gets called from another client, that means the other class is sending a message.

My client class itself:

public class Client implements RMIClientIntf {
    public Client() throws RemoteException { super(); }
    public String getName() throws RemoteException { }
}

Now, the Main class that creates an instance of client calls the following, to send the remote object to the server:

final Client client = new Client();
server.register((RMIClientIntf) client, name);

On the server side, the register method is defined as:

public interface RMIServerIntf extends Remote {
    public String register(RMIClientIntf cl, String userName) throws RemoteException;
    public RMIClientIntf[] get() throws RemoteException;
}


public class Server extends UnicastRemoteObject implements RMIServerIntf {
    public String register(RMIClientIntf cl, String userName) throws RemoteException {
        ClientStruct newClient = new ClientStruct(cl, userName);
        /* Store the ClientStruct */
        return new String("SUCCESS");
    }
}

After registering, each client will request the list of connected users. The function in the server is the following:

public RMIClientIntf[] get() throws RemoteException {
    RMIClientIntf[] users = new RMIClientIntf[openConnections.size()];
    /* Fill in users from ClientStruct */
    return users;
}

If Client were to also implement Serializable, then the program runs but when client2 calls client1.message(), the message() method gets called for client2 and throws a NullPointer at this point.

I was looking at this link: http://www.exampledepot.com/egs/java.rmi/args_Args.html, which gave me a hint that it should implement Remote but not Serialization to pass by reference. I am not sure why the program is complaining in my case.

I really appreciate any help I can get. I've been trying to fix this problem for a while and I can't seem to find any solution.

Thank you very much!

Stook answered 10/9, 2011 at 0:47 Comment(0)
G
2

you need to export Client and send the stub to the server

edit: this should work, it should the same way you exported the server (but without using the rmiregistry)

server.register((RMIClientIntf) UnicastRemoteObject.exportObject(client,0), name);
Glover answered 10/9, 2011 at 1:12 Comment(4)
I am not sure how to do that. Do you have a tutorial please? I currently have the Client.java file part of the classpath and the codebase for the Server, Client, and Interface project (which holds Client.java code).Stook
That code (a) does not compile (b) doesn't make sense and (c) isn't the way he exported the server.Chambertin
@EJP fixed (and exportObject only returns a Remote, not a RMIClientIntf)Glover
Your code wasn't calling exportObject() when I wrote that comment. I'm not a mind reader.Chambertin
C
1

You can't just pass arbitrary references around via RMI. Client would have to be either Serializable, so it gets passed entire to the target, or an exported remote object itself, so a remote reference to it gets passed and it stays put - i.e. it is a callback.

EDIT: as the latter appears to be your intention, all you need to to is make Client extend UnicastRemoteObject.

There is an excellent RMI Trail as part of the Oracle/Sun Java Tutorials.

Chambertin answered 10/9, 2011 at 1:12 Comment(2)
How could I please make an exported remote object iself? Do you please have a simple tutorial?Stook
Awesome! I got it to work, thanks a lot! The code follows: RMIClientIntf stub = (RMIClientIntf) UnicastRemoteObject.exportObject(client, 0); String response = server.register(stub, name);Stook

© 2022 - 2024 — McMap. All rights reserved.