Java RMI and ClassNotFoundException

I tried this example with two PC in same network. One with Java 1.7.0_40 working as server, another with Java 1.7.0_45 as client. Both PCs are Windows based. I met the same problem raised by denshaotoko.

The solution is:

Server side:

C:\>start rmiregistry -J-Djava.rmi.server.useCodebaseOnly=false

The -J-Djava.rmi.server.useCodebaseOnly option is needed for Java 7 since the default value is true, which means the RMI Registry will not look for other code base except the directory it is started from. Then the next step starting the server will fail. Details see here: http://docs.oracle.com/javase/7/docs/technotes/guides/rmi/enhancements-7.html

C:\>java -cp c:\rmi;c:\rmi\compute.jar -Djava.rmi.server.useCodebaseOnly=false -Djava.rmi.server.codebase=file:/c:/rmi/compute.jar -Djava.rmi.server.hostname=192.168.1.124 -Djava.security.policy=c:\rmi\server.policy engine.ComputeEngine

Again the java.rmi.server.useCodebaseOnly should be set to false. Otherwise the server won't use the codebase provided by the client. Then client side will get the class not found exception. The hostname of 192.168.1.124 is the server's IP address

You should get "ComputeEngine bound"

Client side:

C:\>java -cp c:\rmi;c:\rmi\compute.jar -Djava.rmi.server.codebase=http://54.200.126.244/rmi/ -Djava.security.policy=c:\rmi\client.policy client.ComputePi 192.168.1.124 45 

I trid the file:/ URL but not successful. I think the reason is simple. There're so many security limits that make the server not possible to access a file on the client PC. So I put the Pi.class file on my web server which is at http://54.200.126.244 under rmi directory. My web server use Apache. Any PC can access http://54.200.126.244/rmi/ so the problem is solved cleanly.

Finally, you should be able to start the rmiregistry, the server and the client from any directory using the same commands. Otherwise, some settings may still not be correct even if you can succeed. For example, if you start rmiregistry from the directory contain the "compute" directory (in my case is C:\rmi), the rmiregistry will directly load Compute.class and Task.class from it's starting directory, so the setting of -Djava.rmi.server.codebase=file:/c:/rmi/compute.jar become useless.


You are trying to send a serialized object of a class that is unknown to the server.

When you execute:

  Pi task = new Pi(Integer.parseInt(args[1]));
  BigDecimal pi = comp.executeTask(task);

The server doesn't really know what is Pi. And since the Pi class is a part of your API, it should be loaded on server, too.

When I have an application that needs to execute something remotely, using for example RMI, Spring Remoting or similar, I divide my project in 3 projects: API, Server and Client. The API project will have all interfaces and model classes relevant to the functionality (this project will result in a jar, and is more or less like your computer JAR). The server will import the API JAR, will implement the interfaces and make the service available through an Remote layer (like you did with your server), and the client as you did with your client.

When you work with serialization, the class itself must be known by both sides. What is then transferred is the state of the objects in order to rebuild it on the other side.

Serialization is the mechanism used by RMI to pass objects between JVMs, either as arguments in a method invocation from a client to a server or as return values from a method invocation.

A bit of Serialization on RMI By William Grosso (October 2001). And here a bit more info.

Tags:

Java

Rmi

Client