Reputation: 61
I'm trying to get callbacks working in Java using RMI.
I have a server running on AWS. My client succesfully connects to the server and registers the callback. However, while trying to call it I get the following exception on the server side:
java.rmi.NoSuchObjectException: no such object in table
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:162)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at com.sun.proxy.$Proxy3.call(Unknown Source)
at server.SimpleUpdateManager.callAll(SimpleUpdateManager.java:42)
at server.Server$1.run(Server.java:77)
at java.lang.Thread.run(Thread.java:745)
I have no idea why it does happen. I have checked that rc (RemoteCallback implementation instance on the client) is not garbage collected. Do you have any idea why it might not work?
Here are my remote interfaces:
public interface RemoteCallback extends Remote {
void call() throws RemoteException;
}
and
public interface CallbackManager extends Remote{
void register(RemoteCallback uc) throws RemoteException;
void unregister(RemoteCallback uc) throws RemoteException;
void callAll() throws RemoteException;
}
The relevant server code:
public class SimpleUpdateManager implements CallbackManager {
private HashSet<RemoteCallback> callbacks;
public SimpleUpdateManager() {
callbacks = new HashSet<>();
}
@Override
public synchronized void register(RemoteCallback uc) {
callbacks.add(uc);
System.out.println("Callback registered");
}
@Override
public synchronized void unregister(RemoteCallback uc) {
callbacks.remove(uc);
}
@Override
public synchronized void callAll() {
ArrayList<RemoteCallback> toDelete = new ArrayList<>();
for(RemoteCallback rc : callbacks) {
try {
rc.call();
System.out.println(" Called one listener");
} catch (RemoteException re) {
re.printStackTrace();
toDelete.add(rc);
}
}
for(RemoteCallback rc :toDelete)
unregister(rc);
System.out.println("Called all listeners");
}
}
An excerpt from the Server class:
private static SimpleUpdateManager setupUpdateManager() {
String name = "UpdateManager";
SimpleUpdateManager sum = new SimpleUpdateManager();
try {
CallbackManager exp = (CallbackManager) UnicastRemoteObject.exportObject(sum, 1100);
LocateRegistry.getRegistry().rebind(name, exp);
}
catch(RemoteException re) {
System.out.println("Setting up update manager failed");
re.printStackTrace();
}
return sum;
}
public static void runUpdateDaemon(SimpleUpdateManager sum) {
Thread updateDaemon = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
try {
System.out.println("I will try calling all listeners");
sum.callAll();
TimeUnit.SECONDS.sleep(5);
}
catch (InterruptedException ie) {
break;
}
}
}
});
//updateDaemon.setDaemon(true);
updateDaemon.start();
}
And the client code : RemoteCallback implementation
public class SimpleCallback implements RemoteCallback {
@Override
public void call() throws RemoteException {
System.out.println("Callback called");
}
@Override
protected void finalize() {
System.out.println("Callback gc'd");
}
}
and the registering of a callback
try {
rc = new SimpleCallback();
UnicastRemoteObject.exportObject(rc, 1100);
((CallbackManager) LocateRegistry.getRegistry(host).lookup("UpdateManager")).register(rc);
System.out.println("Callback registered");
}
catch (RemoteException|NotBoundException re) {
System.out.println("Cannot register callback");
re.printStackTrace();
}
Upvotes: 2
Views: 4325
Reputation: 61
Here's what the problem was:
The client was behind a firewall which did not allow to access port 1100 from the server, so the DGC assumed that the client has crashed and garbage collected the callback in some way.
Upvotes: 3