RMI callback with JAVA1.5

Since the version 1.5 we have no need to distribute the stub to all the clients.

It's a great feature, but I need to perform a callback from the server to the client, in this case I need to perform a call to UnicastRemoteObject.exportObject()

client-side before calling the registration method exposed by the server, and the stub of the class implementing the callback interface must be placed in the classpath of the server, is it true? Is there any other methos to perform an RMI-callback?

To be clear as much as possible I have this interface exposed by the server

publicinterface Servicesextends Remote

{

public Map<String, ApplicationStatus> applicationsList ()throws RemoteException;

public ApplicationStatus startApplication (String identifier)throws RemoteException;

public ApplicationStatus stopApplication (String identifier)throws RemoteException;

publicint exitCode (String identifier)throws RemoteException;

/**

* This method, as the name says, is used by the client to register the listener to some server-side event.

* @param callback

* @throws RemoteException

*/

publicvoid registerForNotification (ExitCodeCallback callback)throws RemoteException;

}

and the interface of the callback is

publicinterface ExitCodeCallbackextends Remote

{

publicvoid notifyExitCode (ExitCodeEvent event)throws RemoteException;

}

On the server side I export the services in the registry

Services servicesServerSide =new MyServices();

Services services = (Services) UnicastRemoteObject.exportObject(servicesServerSide , 0);

and on the client I perform a lookup of the services

Registry registry = LocateRegistry.getRegistry("192.168.0.1", 1099);

Services services = (Services) registry.lookup("SERVICES");

I export my implementation of the interface

publicclass ClientExitCodeCallbackimplements ExitCodeCallback

{

publicvoid notifyExitCode (ExitCodeEvent event)

{

System.out.println(event.asString());

}

}

through the code

services.registerForNotification(remoteCallback);

but on the calling of this method I obtain a ServerSideException

java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:

java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:

java.lang.ClassNotFoundException: it.sogei.jscheduler.rmi.client.ClientExitCodeCallback_Stub

at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:325)

at sun.rmi.transport.Transport$1.run(Transport.java:153)

at java.security.AccessController.doPrivileged(Native Method)

at sun.rmi.transport.Transport.serviceCall(Transport.java:149)

at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)

at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)

at java.lang.Thread.run(Thread.java:595)

at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:247)

at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)

at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:126)

at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:179)

at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)

at $Proxy0.registerForNotification(Unknown Source)

at it.sogei.jscheduler.rmi.client.StartClient.main(StartClient.java:45)

Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:

java.lang.ClassNotFoundException: it.sogei.jscheduler.rmi.client.ClientExitCodeCallback_Stub

at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:285)

at sun.rmi.transport.Transport$1.run(Transport.java:153)

at java.security.AccessController.doPrivileged(Native Method)

at sun.rmi.transport.Transport.serviceCall(Transport.java:149)

at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)

at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)

at java.lang.Thread.run(Thread.java:595)

Caused by: java.lang.ClassNotFoundException: it.sogei.jscheduler.rmi.client.ClientExitCodeCallback_Stub

at java.net.URLClassLoader$1.run(URLClassLoader.java:200)

at java.security.AccessController.doPrivileged(Native Method)

at java.net.URLClassLoader.findClass(URLClassLoader.java:188)

at java.lang.ClassLoader.loadClass(ClassLoader.java:306)

at java.lang.ClassLoader.loadClass(ClassLoader.java:251)

at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)

at java.lang.Class.forName0(Native Method)

at java.lang.Class.forName(Class.java:246)

at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:430)

at sun.rmi.server.LoaderHandler.loadClass(LoaderHandler.java:165)

at java.rmi.server.RMIClassLoader$2.loadClass(RMIClassLoader.java:620)

at java.rmi.server.RMIClassLoader.loadClass(RMIClassLoader.java:247)

at sun.rmi.server.MarshalInputStream.resolveClass(MarshalInputStream.java:197)

at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1544)

at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1466)

at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1699)

at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)

at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)

at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:290)

at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:279)

... 6 more

Is it true all of the above?

[7127 byte] By [vladtsepesha] at [2007-11-27 0:49:50]
# 1
Wen exporting the client-side callback object, supply a port number, or zero if you don't care. Don't use the exportObject() overload that doesn't take a port number, that version requires a stub class to exist.
ejpa at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 2
The export on the client side is made through theExitCodeCallback remoteCallback = (ExitCodeCallback) UnicastRemoteObject.exportObject(callback, 0);instead ofUnicastRemoteObject.exportObject(callback);Message was edited by: vladtsepesh
vladtsepesha at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 3
Somebody doesn't agree with you. Restart the registry and the server and the client and retest.
ejpa at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 4
I did it so many times.But whatever I do the only way to avoid this kind of Exception, the StubNotfoundException on the server side, is to compile to create the stub and put it in the classpath of the server.
vladtsepesha at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 5
Once a stub exists it will be used. Make sure it is deleted both on the client and server's classpath.Alternatively try -Djava.rmi.server.ignoreStubClasses=true.Genady
genadya at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 6
The stub is not in the client classpath but must be in the server classpath in order to have the callback.
vladtsepesha at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 7
Genady is correct. You don't need the stub at all. Delete it. Or else deploy it to both the client and the server's classpaths.
ejpa at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 8
If I leave the stub out of the classpath of the server I obtain a StubNotFoundException as soon as I call the registration method of the callback, this should mean the server needs the stub, isn't it correct?
vladtsepesha at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 9
Not if the client didn't when it exported it and the server is also running 1.5. If anything in the system is < 1.5 you will need to generate a stub and provide it to both the client and the server.
ejpa at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 10
Both the client and the server run on 1.5 JVM.
vladtsepesha at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 11
Then either(1) if there is a stub file present at the client, it is required at the server too, or(2) if there is no stub file present at the client, the server won't need one either.
ejpa at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 12

1) If there is not the stub of the implementation of the callback interface I receive a ClassNotFoundException raised by the server when I try to register the callback, in which the server let me know it doesn't find the it.sogei.jscheduler.rmi.client.ClientExitCodeCallback_Stub.

2)If there is the stub all seems to work fine.

Message was edited by:

vladtsepesh

vladtsepesha at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 13

If the server gets that exception, it's because the client found and used the stub when it exported its callback, or else the server is running < 1.5.

If the client explicitly cites a port number or zero *and* it is running >= 1.5 *and* there is no stub class, it won't use it; it will create a dynamic stub class; and it will send an object of that class to the server as a parameter to the registration call. If the server is running >= 1.5, it will succesfully deserialize that object, reconstruct the dynamic stub from information in the serialization stream, and execute the registration method implementation.

If the client exports by using a stub class instead of the above, it will create an object of that class and send it to the server as a parameter to the registration call; the server will try to deserialize it; and if it doesn't have the stub class available it will throw that exception.

This is how it works.

ejpa at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...
# 14
Yes, you are rigth, this is how it works. It was my fault, I'm looking for stub classes on the server side, not on the client side.
vladtsepesha at 2007-7-11 23:19:36 > top of Java-index,Core,Core APIs...