Java Remote Method Invocation (RMI) provides a way for a Java program on one machine to communicate with objects residing in different JVMs (i.e. different processes or address spaces). The important parts of the RMI architecture are the stub class, object serialization and the skeleton class. RMI uses a layered architecture where each of the layers can be enhanced without affecting the other layers.
The layers can be summarized as follows:
Application Layer: The client and server program
Stub & Skeleton Layer: Intercepts method calls made by the client. Redirects these calls to a remote RMI service.
Remote Reference Layer: Sets up connections to remote address spaces, manages connections, and understands how to interpret and manage references made from clients to the remote service objects.
Transport layer: Based on TCP/IP connections between machines in a network. It provides basic connectivity, as well as some firewall penetration strategies.
RMI runtime steps involved are:
Step 1: Start RMI registry and then the RMI server. Bind the remote objects to the RMI registry.
Step 2: The client process will look up the remote object from the RMI registry.
Step 3: The lookup will return the stub to the client process from the server process.
Step 4: The client process will invoke method calls on the stub. The stub calls the skeleton on the server process
through the RMI reference manager.
Step 5: The skeleton will execute the actual method call on the remote object and return the result or an exception to the client process via the RMI reference manager and the stub.
What is a remote object ? Why should we extend UnicastRemoteObject ?
A remote object is one whose methods can be invoked from another JVM (i.e. another process). A remote object class must implement the Remote interface. A RMI Server is an application that creates a number of remote objects.
An RMI Server is responsible for
Creating an instance of the remote object (e.g. CarImpl instance = new CarImpl()).
Exporting the remote object.
Binding the instance of the remote object to the RMI registry. By exporting a remote object you make it available to accept incoming calls from the client. You can export the remote object by either extending the java.rmi.server.UnicastRemoteObject or if your class is already extending another class then you can use the static method
If the UnicastRemoteObject is not extended (i.e. if you use UnicastRemoteObject.exportObject("") then the implementation class is responsible for the correct implementations of the hashCode(), equals() and toString() methods. A remote object is registered in the RMI registry using:
Java only solution. The interfaces, implementations and the clients are all written in Java.
RMI allows dynamic loading of classes at runtime.
CORBA was made specifically for interoperability among various languages. For example the server could be written in C++ and the business logic can be in Java and the client can be written in COBOL.
In a CORBA environment with multi-language support it is not possible to have dynamic loading.
What are the services provided by the RMI Object ?
In addition to its remote object architecture, RMI provides some basic object services, which can be used in a distributed application. These services are
Object naming/registry service: RMI servers can provide services to clients by registering one or more remote objects with its local RMI registry.
Object activation service: It provides a way for server (i.e. remote) objects to be started on an as-needed basis. Without the remote activation service, a server object has to be registered with the RMI registry service.
Distributed garbage collection: It is an automatic process where an object, which has no further remote references, becomes a candidate for garbage collection.
What are the differences between RMI and a socket ?
A socket is a transport mechanism. Sockets are like applying procedural networking to object oriented environment.
Sockets-based network programming can be laborious.
RMI uses sockets. RMI is object oriented. Methods can be invoked on the remote objects running on a separate JVM.
RMI provides a convenient abstraction over raw sockets. Can send and receive any valid Java object utilizing underlying object serialization without having to worry about using data streams.
How will you pass parameters in RMI ?
Primitive types are passed by value (e.g. int, char, boolean etc).
References to remote objects (i.e. objects which implement the Remote interface) are passed as remote references that allow the client process to invoke methods on the remote objects.
Non-remote objects are passed by value using object serialization. These objects should allow them to be serialized by implementing the java.io.Serializable interface.
Note: The client process initiates the invocation of the remote method by calling the method on the stub. The stub (client side proxy of the remote object) has a reference to the remote object and forwards the call to the skeleton (server side proxy of the remote object) through the reference manager by marshaling the method arguments. During Marshaling each object is checked to determine whether it implements java.rmi.Remote interface. If it does then the remote reference is used as the Marshaled data otherwise the object is serialized into byte streams and sent to the remote process where it is deserialized into a copy of the local object. The skeleton converts this request from the stub into the appropriate method call on the actual remote object by unmarshaling the method arguments into local stubs on the server (if they are remote reference) or into local copy (if they are sent as serialized objects).
What is HTTP tunneling or how do you make RMI calls across firewalls ?
RMI transport layer generally opens direct sockets to the server. Many Intranets have firewalls that do not allow this. To get through the firewall an RMI call can be embedded within the firewall-trusted HTTP protocol. To get across firewalls, RMI makes use of HTTP tunneling by encapsulating RMI calls within an HTTP POST request. When a firewall proxy server can forward HTTP requests only to a well-known HTTP port: The firewall proxy server will forward the request to a HTTP server listening on port 80, and a CGI script will be executed to forward the call to the target RMI server port on the same machine. The disadvantages of HTTP tunneling are performance degradation, prevents RMI applications from using callbacks, CGI script will redirect any incoming request to any port, which is a security loophole, RMI calls cannot be multiplexed through a single connection since HTTP tunneling follows a request/response protocol etc.
Why use RMI when we can achieve the same benefits from EJB ?
EJBs are distributed components, which use the RMI framework for object distribution. An EJB application server provides more services like transaction management, object pooling, database connection-pooling etc, which RMI does not provide. These extra services that are provided by the EJB server simplify the programming effort at the cost of performance overhead compared to plain RMI. So if performance is important then pure RMI may be a better solution (or under extreme situations Sockets can offer better performance than RMI).