Remote Method Invocation (RMI):
RMI allows a developer to abstract away where objects physically reside from his application.
Typical desktop client applications can then access these objects as if they were local and part of the same object-oriented application.
Location independent objects are powerful because they can be dynamically moved around from machine to machine.
If mail services’ objects on a server become too bogged down, they can be spread across multiple machines, all transparently to the client applications using them.
Java’s platform independence adds even more value to its location-independent objects.
Server objects could reside on a Unix-based operating system for example and client objects on a Microsoft Windows platform.
RMI -- Remote Method Invocation
The Remote Method Invocation (RMI) is an API that provides a mechanism to create a distributed application in java.
RMI is the Java platform for remote procedure calls.
RMI calls can happen over a network, and b/w two separate processes.
There is a client and a server program running on a separate machine ( or two separate processes on the same machine).
The client program calls a procedure(method) on the server and waits until the server returns the method result. Thus the RMI allows an object to invoke methods on an object running in another JVM.
Core RMI principles
In order to call methods on a remote object, three main steps occur:
1. A reference to the remote object must be obtained.
The remote object must be looked up on the remote server.
2. Marshalling and unmarshalling of parameters.
When a method is invoked on the remote reference, the parameters must be marshaled into a byte stream that can be sent over the network. On the server side, these parameters must be unmarshaled from the byte stream into their original values and then passed to the appropriate method.
3. Transmission of data through a common protocol.
There must be a protocol defined for the transport and delivery of these method calls and returns. A standard format for parameters is necessary, along with standards to tell the server which method on which object is to be invoked.Understanding Stub and Skelton
RMI uses stub and skeleton object for communication with the remote object.
Remote Object
A remote object is an object whose method can be invoked from another JVM.
Let's understand the stub and skeleton objects:
To make the remote call appear like a local call, a local implementation exists with the same interface (all RMI objects must be defined as Java interfaces). This local implementation is called a stub and is essentially a proxy to the real implementation. Whenever a method is called on this local implementation or stub, the local implementation performs the operations necessary to send the method call to a remote implementation of the same interface on another server.
The stub marshals the parameters and sends them over the network using a common RMI protocol.
In turn, a stub on the server side implementing the same interface unmarshals the parameters and then passes them on to the actual remote object in a normal method call. This process is reversed for the return value; the stub on the server side marshals and sends it, and the stub on the client unmarshals and returns it to the original caller.
Stub
The stub is an object, acts as a proxy to the real implementation for the client side. All the outgoing requests are routed through it. It resides at the client side and represents the remote object. When the caller invokes a method on the stub object, it does the following tasks:
- It initiates a connection with remote Virtual Machine (JVM),
- It writes and transmits (marshals) the parameters to the remote Virtual Machine (JVM),
- It waits for the result
- It reads (unmarshals) the return value or exception, and
- It finally, returns the value to the caller.
Skeleton
The skeleton is an object, acts as a gateway for the server side object. All the incoming requests are routed through it. When the skeleton receives the incoming request, it does the following tasks:
- It reads the parameter for the remote method
- It invokes the method on the actual remote object, and
- It writes and transmits (marshals) the result to the caller.
Note: In the Java 2 SDK, a stub protocol was introduced that eliminates the need for skeletons.
Marshaling and Unmarshalling
The parameters and method call must be flattened into a byte stream before they can be sent over the network. This process is called marshaling.
The reverse is called unmarshalling when the byte stream is decoded into the original parameters and method call information.
After unmarshalling the parameters and method call, the server dispatches the method call to the appropriate object that actually implements the remote method and then marshals the return value back to the client.
By serializing the parameters and method into a byte stream,
RMI parameter passing
It can work on top of network protocols that provide a reliable byte stream, such as TCP/IP.
In RMI, two types of objects besides primitives can be passed as parameters:
- objects that implement the java.rmi.Remote interface or
- objects that implement the java.io.Serializable interface.
These two interfaces do not contain any methods, instead, they mark objects with a particular property.
Java’s RMI mechanism knows that Remote objects could be on another virtual machine, and will have stubs.
Objects that implement Serializable, on the other hand, can be transformed into a byte stream (to save to disk, or in RMI’s case, to send over a network).
In RMI, objects that implement Remote are passed by reference, whereas objects that implement Serializable (and not Remote) are passed by value.
When parameters are marshaled over the network and transformed into a byte stream, any object that must be passed via an RMI call must be Serializable. So now for the first time, objects in Java can
be passed by value.
Remote objects are passed by reference and Serializable objects are passed by value.
This helps reduce the number of network calls that must occur.
If an object being passed contains a large number of properties that must be accessed through getXXX methods, there would be a large number of network calls taking place.
By serializing the object, all these calls become local calls on the remote server and use up far less network bandwidth.
Method calls on Remote objects passed in, on the other hand, will go over the network and must be taken into consideration.
Protocols
RMI is implemented such that it can support more than one underlying transport protocol (though obviously only one protocol can be used between any two objects).
There are two main choices as the transport protocol for RMI:
- Java Remote Method Protocol (JRMP)
- JRMP is the default protocol for RMI.
- Internet InterORB Protocol (IIOP)
- IIOP offers compatibility with CORBA,
IIOP, because it was not designed specifically for Java remote procedure calls, does not support some of the features JRMP supports, such as security and distributed garbage collection.
Using IIOP as the underlying protocol for RMI makes it easy to integrate legacy objects written in other languages, IIOP stubs differ from JRMP stubs and must be generated separately.
RMI Registry
Object instances must be made available in a registry on the server before they can be used by remote clients.
Clients obtain an instance by looking up a particular name —for example, the string “EmployeeData” might refer to a class containing the data for the employees of a particular company.
When a server is starting up, it creates instances of the objects it wishes to be available, and registers them in a registry. Because these objects are globally available, they must be thread-safe (because their methods can be called at the same time by
different threads).
The code to look up a particular instance of a class is not very difficult, and uses the Java Naming and Directory Interface (JNDI) API (found in javax.naming). Asmall snippet of code to look up an object on a remote server follows:
import javax.naming.InitialContext;
...
InitialContext ctx = new InitialContext();
EmployeeData data = (EmployeeData) ctx.lookup(“CompanyX\\MyEmployeeDataInstance”);
JNDI is configured by setting certain Java system properties to tell it the location and protocol of the registry.
This is how objects can be transparently remote or local. If the registry is configured locally, in the same JVM, then all calls to data will be local.
If data is an instance on a remote server, all calls will go through RMI, using whatever protocol was specified.
Binding and lookup -- API
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.
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.
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.
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.
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.
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.
Steps to writing the RMI program
The is given the 6 steps to write the RMI program.
1. Create the remote interface
2. Provide the implementation of the remote interface
3. Compile the implementation class and create the stub and skeleton objects using the rmic tool
4. Start the registry service by rmiregistry tool
5. Create and start the remote application
6. Create and start the client application
Example
Step - 1: create a remote interface "CalRemote"
import java.rmi.*;
public interface CalRemote extends Remote
{
public int sum(int a,int b) throws RemoteException;
}
It contains the method provided for the clients.
Clients will have a copy of this interface to interact with RemoteObject
Step - 2 : create a RemoteObject class - CalRemoteImpl.java
import java.rmi.*;
import java.rmi.server.*;
public class CalRemoteImpl extends UnicastRemoteObject implements CalRemote
{
public CalRemoteImpl()throws RemoteException
{}
public int sum(int a,int b) throws RemoteException
{
return (a+b);
}
}
}
Step - 3 : create a Server class -- ServerDemo.java
import java.rmi.*;
class ServerDemo
{
public static void main(String s[])
{
try
{
CalRemoteImpl server=new CalRemoteImpl();
Naming.rebind("calculator",server);
System.out.println("Server is up....");
}
catch(Exception e)
{
System.out.println("error in running Server "+e);
}
}
}
Step - 4 : create a client class -- RmiClient.java
import java.rmi.*;
public class RmiClient
{
public static void main(String s[])
{
try
{
CalRemote rm = (CalRemote)Naming.lookup("rmi://127.0.0.1/calculator");
int rs=rm.sum(4,5);
System.out.println("result : "+rs);
}
catch(Exception e)
{
System.out.println("error in looking Server"+e);
}
}
}
For running this rmi example,
1) compile all the java files
javac *.java
2)create stub and skeleton object by rmic tool
rmic CalRemoteImpl
3) start rmi registry in one command prompt
start rmiregistry 5000
it will bind the port number 5000 for rmi services.
4)start the server in another command prompt
java ServerDemo
5)start the client application in another command prompt
java RmiClient
No comments:
Post a Comment