Wednesday, September 30, 2015

Getting Started with Simple RMI services

Writing your own RMI services can be a little difficult at first, so we'll start off with an example which isn't too ambitious.In this example, we have followed all the 6 steps to create and run the rmi application. The client application need only two files, remote interface and client application. In the rmi application, both client and server interacts with the remote interface. The client application invokes methods on the
proxy object, RMI sends the request to the remote JVM. The return value is sent back to the proxy object and then to the client application.

The is given the 6 steps to write the RMI program.

1.create the remote interface

An interface is a method which contains abstract methods; these methods must be implemented by another class.For creating the remote interface, extend the Remote interface and declare the RemoteException with all the methods of the remote interface. Here, we are creating a remote interface that extends the Remote interface.

import java.math.BigInteger;
import java.rmi.*;

//
// PowerService Interface
//
// Interface for a RMI service that calculates powers
//
public interface PowerService extends Remote
{
 // Calculate the square of a number
 public BigInteger square ( int number )
  throws RemoteException;

 // Calculate the power of a number
 public BigInteger power  ( int num1, int num2) 
  throws RemoteException;
}

2) Provide the implementation of the remote interface

Now provide the implementation of the remote interface. For providing the implementation of the Remote interface, we need to
  • Either extend the UnicastRemoteObject class,
  • or use the exportObject() method of the UnicastRemoteObject class
In case, you extend the UnicastRemoteObject class, you must define a constructor that declares RemoteException. Our implementation of the service also needs to have a main method. The main method will be responsible for creating an instance of our PowerServiceServer, and registering (or binding) the service with the RMI Registry. 
Now rmi services need to be hosted in a server process. The Naming class provides methods to get and store the remote object. The Naming class provides 5 methods.

  1. public static java.rmi.Remote lookup(java.lang.String) throws java.rmi.NotBoundException, java.net.MalformedURLException, java.rmi.RemoteException; it returns the reference of the remote object.
  2. public static void bind(java.lang.String, java.rmi.Remote) throws java.rmi.AlreadyBoundException, java.net.MalformedURLException, java.rmi.RemoteException; it binds the remote object with the given name.
  3. public static void unbind(java.lang.String) throws java.rmi.RemoteException, java.rmi.NotBoundException, java.net.MalformedURLException; it destroys the remote object which is bound with the given name.
  4. public static void rebind(java.lang.String, java.rmi.Remote) throws java.rmi.RemoteException, java.net.MalformedURLException; it binds the remote object to the new name.
  5. public static java.lang.String[] list(java.lang.String) throws java.rmi.RemoteException, java.net.MalformedURLException; it returns an array of the names of the remote objects bound in the registry.

import java.math.*;
import java.rmi.*;
import java.rmi.server.*;

//
// PowerServiceServer
//
// Server for a RMI service that calculates powers
//
public class PowerServiceServer extends UnicastRemoteObject
implements PowerService
{
    public PowerServiceServer () throws RemoteException
    {
        super();
    }

    // Calculate the square of a number
    public BigInteger square ( int number ) 
    throws RemoteException
    {
        String numrep = String.valueOf(number);
        BigInteger bi = new BigInteger (numrep);
        
        // Square the number
        bi.multiply(bi);

        return (bi);
    }

    // Calculate the power of a number
    public BigInteger power ( int num1, int num2)
    throws RemoteException
    {
        String numrep = String.valueOf(num1);
        BigInteger bi = new BigInteger (numrep);

 bi = bi.pow(num2);

 return bi;
    }

    public static void main ( String args[] ) throws Exception
    {
        // Create an instance of our power service server ...
        PowerServiceServer svr = new PowerServiceServer();

        // ... and bind it with the RMI Registry
        Naming.bind ("PowerService", svr);

        System.out.println ("Service bound....");
    }
}

   

5) Create and run the client application

Writing clients is the easy part - all a client has to do is call the registry to obtain a reference to the remote object, and call its methods. At the client we are getting the stub object by the lookup() method of the Naming class and invoking the method on this object. All the underlying network communication is hidden from view, which makes RMI clients simple. In this example, we are running the server and client applications, You can run the client locally, or from a different machine. In either case, you'll need to specify the hostname of the machine where you are running the server. If you're running it locally, use localhost as the hostname.If you want to access the remote object from another machine, change the localhost to the host name (or IP address) where the remote object is located.

  To identify a service, we specify an RMI URL. The URL contains the hostname on which the service is located, and the logical name of the service. This returns a PowerService instance, which can then be used just like a local object reference. We can call the methods just as if we'd created an instance of the remote PowerServiceServer ourselves.


import java.rmi.*;
import java.rmi.Naming;
import java.io.*;


//
// PowerServiceClient
//

public class PowerServiceClient 
{
 public static void main(String args[]) throws Exception
 {
  // Check for hostname argument
  if (args.length != 1)
  {
   System.out.println
   ("Syntax - PowerServiceClient host");
   System.exit(1);
  }


  // Call registry for PowerService
  PowerService service = (PowerService) Naming.lookup
   ("rmi://" + args[0] + "/PowerService");

  DataInputStream din = new 
   DataInputStream (System.in);

  for (;;)
  {
   System.out.println 
     ("1 - Calculate square");
   System.out.println 
     ("2 - Calculate power");
   System.out.println 
     ("3 - Exit"); System.out.println();
   System.out.print ("Choice : ");

   String line = din.readLine();
   Integer choice = new Integer(line);
   
   int value = choice.intValue();

   switch (value)
   {
   case 1:
     System.out.print ("Number : ");
     line = din.readLine();System.out.println();
     choice = new Integer (line);
     value  = choice.intValue();
    
     // Call remote method
     System.out.println 
     ("Answer : " + service.square(value));
    
     break;
   case 2:
     System.out.print ("Number : ");
     line = din.readLine();     
     choice = new Integer (line);
     value  = choice.intValue();
    
     System.out.print ("Power  : ");
     line = din.readLine();
     choice = new Integer (line);
     int power = choice.intValue();

     // Call remote method
     System.out.println 
  ("Answer : " + service.power(value, power));

     break;
   case 3:
     System.exit(0);
   default :
     System.out.println ("Invalid option");
   break;
   }
  }
 }
}

Steps To Test

1) compile all the java files 

javac *.java  
 
2)create stub and skeleton object by rmic tool 
 
rmic PowerServiceServer 
 
3)start rmi registry in one command prompt 
 
rmiregistry 5000  
 
4)start the server in another command prompt 
 
java PowerServiceServer 
 
5)start the client application in another command prompt 
 
java PowerServiceClient localhost 


Output



References