3

I have a server and a client communicating through RMI. Their goal is to share a simple object, work on it together, and then simulate a server disconnect.

The sever has its name bound to the rmiregistry. The client uses the rmiregistry to get a remote reference to the server. Then it uses this reference to call a method that returns a reference to the object they will share. Further communication is to be done through this shared object.

The shared object is a UnicastRemoteObject, the server owns its implementation and has a method the returns a reference to the client.

The client knows the interface of the shared object, gets a remote reference from the server and then acts on it. Please note the server should return a remote reference, not a serialized copy.

This is the shared object interface

public interface CInterface extends Remote {
    boolean testMethod() throws RemoteException;
}

And this is its implementation

public class CImpl implements CInterface {
    @Override
    public boolean testMethod() throws RemoteException {
        return false;
    }
}

This is the method of the server that should return a remote reference when the client calls it

public CInterface exportRefToC() throws RemoteException {
    return new CImpl();
}

If I call it from the client, it gives me this exception

java.rmi.UnmarshalException: error unmarshalling return; nested exception is: java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: sandbox.CImpl

I can get the method to work and return a remote reference if I write it this way

public CInterface exportRefToC() throws RemoteException {
    refToC = new CImpl();
    return (CInterface) UnicastRemoteObject.exportObject(refToC, 1099);
}

What I don't get is why I need to go through the registry again, though not explicitly binding a the name, just to return a remote reference. The client got a reference to the server before, using the rmiregistry, so the bootstrap is done. Now, why can't the server just return a reference to the client without knowing the port of the rmiregistry (1099)?

Bonus question, if the server wants to make the object it shared with the client unavailable (to simulate a disconnection), is there a better way than doing this

UnicastRemoteObject.unexportObject(refToC, true);

EDIT: if I extend the UnicastRemoteObject in the implementation of the shared object, the first version of the method works, however, the unexport does not work and return this exception

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: java.rmi.NoSuchObjectException: object not exported

EDIT2: checked again, it does work, just need to save the reference before returning it

public CInterface exportRefToC() throws RemoteException {
    refToC = new CImpl();
    return refToC;
}

1 Answer 1

2

The shared object is a UnicastRemoteObject

No it isn't. Look again:

public class CImpl implements CInterface

Add extends UnicastRemoteObject to that, and provide an appropriate constructor, and your problem will disappear.

You don't need to call exportObject(), and you don't need a second binding to the Registry.

Your last question embodies a mistake. It should be unexportObject(), and that is the correct way of making the object unavailable.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.