Since my early days with Java many stuff have impressed me but, among the things that impressed me the most, is the Remote Method Invocation (RMI). It makes it very easy to create applications over a network. One hard part about it was that we had to create what we call “Stub files” for each class that was published on our registry (a.k.a. Remote objects). Since JDK 5 though this was history. One of the new features was that the Stub class was generated automaticaly and no further action was needed…, or not quite like that?

Let’s break things up a little and see what was actually happening. Let’s say we have the following small server. It has a Server interface that is actually the class that extends Remote and the ServerImplementor that implements the Server (as the name says) and creates the Registry exporting the objects to it. Let’s have a look.

Server.java

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Server extends Remote {
	public void doSomething() throws RemoteException;
}

ServerImplementor.java

import java.rmi.RemoteException;
import java.rmi.Remote;
import java.rmi.server.UnicastRemoteObject;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class ServerImplementor implements Server {
	
	public static void main(String args[]){
		try{
			(new ServerImplementor()).exportServer();
		} catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void exportServer() throws Exception{
		Remote obj = UnicastRemoteObject.exportObject(this, 10000);
		Registry r = LocateRegistry.createRegistry(10000);
		r.bind("test", obj);
	}
	
	public void doSomething() throws RemoteException{
		System.out.println("hahah");
	}

}

The above is a fully working example of an RMI server. On a JDK less than 1.5, that is 1.4 or smaller one would have to do “javac *.java” and then “rmic ServerImplementor.class” that would produce a file ServerImplementor_Stub.class. This is the so called Stub file.

On the client side we would have to copy the Server.class file (which is the interface that extends remote showing the services that the server has) and the ServerImplementor_Stub.class. If the Stub file was missing we would get an UnmarshalException because of the stub file missing.

So, for each build of our application, and when we develop we do that alot, we would have to rmic and then copy the files. Very frustrating if you ask me. Since JDK 1.5 Sun introduced the feature that one wouldn’t have to go through all the trouble of the stub making process. Ofcourse the client would have to have the Server.class because it would have to have a way of finding out the methods exported to the RMI registry. BUT if you try running the above example on JDK 1.5, or even on JDK 1.6, without the stub file, you would get this exception:

java.rmi.StubNotFoundException: Stub class not found: ServerImplementor_Stub; nested exception is:
        java.lang.ClassNotFoundException: ServerImplementor_Stub
        ...

Now this is quite weird huh? Once more, though, the acronym “RTFM” (Read The Fine(??) Manual) comes at hand. I discovered the solution to this by accident when i noticed the method signatures on the UnicastRemoteObject that exports the Remote object. I was, also, going through all the trouble of creating the Stub file without knowing why. So, if you have not already visited the api specification on the UnicastRemoteObject, please do so now. Scroll down to the method we used on line 18 of the ServerImplementor which is the exportObject(Remote obj). Now see the return type of the method? RemoteStub! Houston we have a problem…! Here is where all the fuss is created. Now notice the method just below that, exportObject(Remote obj, int port). This returns a pure Remote object.

Now one would say, if we get a RemoteStub is it the same with Remote? Well check the RemoteStub class. It extends the class RemoteObject which implements the Remote interface. So here it is, cloacked under the RemoteStub file creating all the trouble. So if you are among those still having problem with that, export your object on a standard port (the same you create your Registry on) and everything should work just fine.

Hope this helped clearing things out. As always comments are more than welcome!