Tuesday, February 16, 2010

Java RMI step by step


I got an opportunity to analyse different distributed java computing technologies like EJB3, CORBA, Web Services etc. One of them was the Java RMI. I got a chance to develop a sample application in Java RMI and RMI-SSL and I would like to share my implementation experience and the problems faced.

Step 1
Create an interface which extends the java.rmi.Remote interface. This interface is used by the client to access the RMI stub class generated in the later steps.
Following is the interface which extends Remote

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

        public interface GreetingProvider extends Remote {
                String getGreeting() throws RemoteException;
        }



Step 2

Create a policy file which will define rights and permissions for the server as well as the client to access the remote objects. The file given below is an example file and AllPermission is not suitable for the production kind of environment. It is solely for learning and understanding RMI
create a file with the name java.security.policy as follows:
        grant
        {
              permission java.security.AllPermission;
        };

 



Step3
Create a server class which will implement the GreetingProvider interface. This class will reside in the server and will have the actual implementation of the method. This method will then be invoked remotely by the client using the common GreetingProvider interface defined in step 1.
Following is the implementing server class


        import java.net.MalformedURLException;
        import java.rmi.AlreadyBoundException;
        import java.rmi.Naming;
        import java.rmi.RMISecurityManager;
        import java.rmi.RemoteException;
        import java.rmi.server.UnicastRemoteObject;
        import com.rmi.test.remote.interfaces.GreetingProvider;

        public class GreetingServer implements GreetingProvider{

        protected GreetingServer() {
             super();
        }
        public static void main(String[] args) {
        System.setProperty("java.security.policy", "E:/Research_WS/RMITEST2   /java.security.policy"); // set property java.security.policy and give the path of the //java.security.policy file created in step 2
              
        if (System.getSecurityManager() == null)
            System.setSecurityManager ( new RMISecurityManager() );
       
        try {
            GreetingProvider server = new GreetingServer();
            GreetingProvider stub = (GreetingProvider)
                UnicastRemoteObject.exportObject(server); // returns the stub class
           
            Naming.bind("GreetingServer", stub);
            System.out.println("service bound");
        } catch (RemoteException e) {
             e.printStackTrace();
        } catch (MalformedURLException e) {
             e.printStackTrace();
        } catch (AlreadyBoundException e) {
             e.printStackTrace();
        }
    }

    @Override
    public String getGreeting() {
        return "Hello World";
    }
}



Step 4
Create the client class. This class will obtain the remote server object through a stub class which will be generated in the steps below. This client is residing on the same JVM as the server machine. In case it should reside in a separate JVM, then the GreetingProvider interface,java.security.policy and stub class needs to be exported to the client through a jar file.
Client class code is as follows:

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import com.rmi.test.remote.interfaces.GreetingProvider;

public class GreetingClient {

    public static void main(String args[])
    {
        System.setProperty("java.security.policy", "E:/Research_WS/RMITEST2               /java.security.policy");
        System.out.println(System.getProperty("java.security.policy"));
        if (System.getSecurityManager() == null)
        {
            System.setSecurityManager
            (new RMISecurityManager());
        }
   
        try {
            GreetingProvider service = (GreetingProvider) Naming.lookup
                ("rmi://localhost:1099/GreetingServer");
            System.out.println(service.getGreeting());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (NotBoundException e) {
            e.printStackTrace();
        }
    }
}






Step 5
Compile the interface,server, client classes prepared in the above steps. If you are not using an IDE you can compile using the javac command from the command prompt.



Step 6
Start the rmi registry using the start rmiregistry command
using the rmic command compile the server class (not the .java file but the .class file generated after javac compilation of the server class) . A stub will be generated after this command. This stub is the client stub that will be actually referencing our remote server object. 


Step 7
Now run the server (rmi registry is still on) i.e let the main method execute. But there is a codebase Virtual machine arguement that is to be added while running. It can be done as follows:
-Djava.rmi.server.codebase=file:/e:/Research_WS/RMITEST2/bin/
give the path where you will be able to find the stub class (.class)


Step 8
Run the client.


Output
Hello World

The policy file and the codebase virtual machine property are quite important and are prone to be forgotten. Also the rmiregistry should be started when you run the server and the client. You can also start the registry at a particular port by default the port is 1099.