Remote Method Invocation (RMI)

Socket based communications requires that you make explicit connections between servers and clients and transmit data through those connections. The Remote Method Invocation (RMI) in Java simplifies this situation by not requiring you to make explicit connections. Objects located on remote hosts can through this framework be accessed as if they were situated locally. The underlying connection and transmission of data are handled implicitly by the JVM. These are some terms that you must be familiar with: The client and server classes are written by programmers. The stubs and skeletons are created by the RMI compiler from the server code. This is how the RMI process works:
  1. The client invokes a method that is offered by the server. The invocation is received by the stub.
  2. The stub arranges the request and data in a linear stream. This is known as marshalling and sends that information to the machine that the server resides on.
  3. The skeleton receives the request and unmarshals the information and invokes the method on the server object.
  4. The server executes the method and returns the result to the skeleton.
  5. The skeleton marshals the result and sends it to the stub.
  6. The stub unmarshals the result and sends the result to the client object.

In this simple example on Remote Method Invocation, the server offers the services of a calculator that can perform elementary arthimetic operations. These are the steps that you would need to perform to set up the system. The sample code is appended below.

  1. Clients must know what services the Calculator Server provides.
    RMI: ICalculator interface lists the methods available to remote clients.
  2. Clients must find a Calculator object on the server.
    RMI: The Calculator Server registers an object with a special server, called the rmiregistry, so that clients can look it up by name.
  3. Clients must be able to pass arguments to, and invoke a method of the Calculator object located on the server. RMI: A special compiler called rmic creates a stub class for use on the client, and a skeleton class for use on the server. The stub takes the request from the client, passes the arguments to the skeleton which invokes the Calculator methods, and send the return value back to the stub which passes it to the client.
To set up the RMI example do the following:
On the server machine:
  1. Compile ICalculator.java, Calculator.java, and CalculatorServer.java
  2. Create the stub and skeleton classes using the command rmic Calculator
  3. Copy the Calculator_Stub.class to the client site
  4. Start the registry using the command rmiregistry&
  5. Start CalculatorServer using java CalculatorServer serverHostname &
On the client machine:
  1. Compile ICalculator.java and CalculatorClient.java
  2. Run CalculatorClient using the command java CalculatorClient serverHostname
/*
   Interface for the Calculator class
*/

import java.rmi.*;

public interface ICalculator extends java.rmi.Remote
{
  public long add (long a, long b) throws java.rmi.RemoteException;
  public long sub (long a, long b) throws java.rmi.RemoteException;
  public long mul (long a, long b) throws java.rmi.RemoteException;
  public long div (long a, long b) throws java.rmi.RemoteException;
}


/*
   Implementation of the ICalculator interface. This class offers
   the service that clients can invoke.
*/

import java.rmi.*;

public class Calculator extends java.rmi.server.UnicastRemoteObject
			implements ICalculator
{
  public Calculator() throws java.rmi.RemoteException
  {
    super();
  }

  public long add (long a, long b) throws java.rmi.RemoteException
  {
    return a + b;
  }

  public long sub (long a, long b) throws java.rmi.RemoteException
  {
    return a - b;
  }

  public long mul (long a, long b) throws java.rmi.RemoteException
  {
    return a * b;
  }

  public long div (long a, long b) throws java.rmi.RemoteException
  {
    return a / b;
  }
}


/*
  This class starts the server that offers the CalculatorService
  to clients.
*/

import java.rmi.*;

public class CalculatorServer
{
  public CalculatorServer(String s)
  {
    try
    {
      ICalculator c = new Calculator();
      String url = "rmi://" + s + ":1099/CalculatorService";
      Naming.rebind (url, c);
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }

  public static void main (String[] args)
  {
    new CalculatorServer (args[0]);
  }
}


/*
   This is a client of the Calculator Service offered by the
   Calculator class at a remote site.
*/

import java.rmi.*;

public class CalculatorClient
{
  public static void main (String[] args)
  {
    try
    {
      String url = "rmi://" + args[0] + ":1099/CalculatorService";
      ICalculator c = (ICalculator) Naming.lookup (url);
      System.out.println (c.add(3, 5));
      System.out.println (c.sub(9, 5));
      System.out.println (c.mul(3, 5));
      System.out.println (c.div(15, 5));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
}