RMI (Remote Method Invocation) Java
The most fundamental means of inter-object communication in Java is method invocation. When we want to communicate between virtual machines on different hosts, it’s natural to want similar capabilities and semantics mechanisms. Java’s Remote Method Invocation mechanism does just that. It lets us get a reference to an object on a remote host and use it as if it were in our virtual machine. RMI lets us invoke methods on remote objects, passing real Java objects as arguments and getting real Java objects as returned values.
Remote & Non-Remote Objects:
Before an object can be used remotely through RMI, it must be serializable. But that’s not sufficient. Remote objects in RMI are real distributed objects. As the name suggests, a remote object can be an object on a different machine or an object on the localhost. Non Remote objects are simpler; they’re just normal serializable objects. The catch is that when you pass a non-remote object over the network, it is simply copied, so references to the object on one host are not the same as those on the remote host.
A remote object is an instance of a class that implements a remote interface. A remote interface extends the interface java.rmi.Remote and declares a set of remote methods. Each remote method must declare java.rmi.RemoteException (or a superclass of RemoteException) in its throws clause, in addition to any application-specific exceptions. The reason for declaring RemoteException is that remote method invocations can fail in many additional ways compared to local method invocations such as network-related communication problems and server problems, and remote methods will report such failures by throwing a java.rmi.RemoteException. Below is the code of Remote Interface.
A “server” class, in this context, is the class that has a main method that creates an instance of the remote object implementation, exports the remote object, and then binds that instance to a name in a Java RMI registry. The class that contains this main method could be the implementation class itself, or another class entirely.
The implementation class Server implements the remote interface, Hello, providing an implementation for the remote method sayHello( ). The method sayHello( ) does not need to declare that it throws an exception because the method implementation itself does not throw RemoteException nor does it throw any other checked exceptions.
A class can define methods not specified in the remote interface, but those methods can only be invoked within the virtual machine running the service and cannot be invoked remotely. The server’s main method creates and exports a remote object & Registers the remote object with a Java RMI registry.
Exporting remote objects
The static method UnicastRemoteObject.exportObject exports the supplied remote object to receive incoming remote method invocations on an anonymous TCP port and returns the stub for the remote object to pass to clients. As a result of the exportObject call, the runtime may begin to listen on a new server socket or may use a shared server socket to accept incoming remote calls for the remote object. The returned stub implements the same set of remote interfaces as the remote object’s class and contains the hostname and port over which the remote object can be contacted.
Server obj = new Server();
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);
RMI uses stub and skeleton objects for communication with the remote object. The stub is an object, acts as a gateway 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 the method on the stub object: It initiates a connection with remote JVM, it writes and transmits (marshals) the parameters to the remote JVM, it waits for the result, it reads (unmarshals) the return value or exception, and it finally, returns the value to the caller.
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 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.
The RMI Registry:
For a caller (client, peer, or applet) to be able to invoke a method on a remote object, that caller must first obtain a stub for the remote object. For bootstrapping, Java RMI provides a registry API for applications to bind a name to a remote object’s stub and for clients to lookup remote objects by name to obtain their stubs.
A Java RMI registry is a simplified name service that allows clients to get a reference (a stub) to a remote object. In general, a registry is used (if at all) only to locate the first remote object a client needs to use. Then, typically, that first object would in turn provide application-specific support for finding other objects. For example, the reference can be obtained as a parameter to, or a return value from, another remote method call. Once a remote object is registered on the server, callers can look up the object by name, obtain a remote object reference, and then invoke remote methods on the object.
Registry registry = LocateRegistry.getRegistry();
The static method LocateRegistry.getRegistry that takes no arguments returns a stub that implements the remote interface java.rmi.registry.Registry sends invocations to the registry on the server’s localhost on the default registry port of 1099. The bind method is then invoked on the registry stub to bind the remote object’s stub to the name” From Code” in the registry. The call to LocateRegistry.getRegistry simply returns an appropriate stub for a registry. The call does not check to see if a registry is running. If no registry is running on TCP port 1099 of the local host when the bind method is invoked, the server will fail with a RemoteException.
The client program obtains a stub for the registry on the server’s host, looks up the remote object’s stub by name in the registry, and then invokes the sayHello( ) method on the remote object using the stub.
This client-first obtains the stub for the registry by invoking the static LocateRegistry.getRegistry method with the hostname specified on the command line. If no hostname is specified, then null is used as the hostname indicating that the localhost address should be used. Next, the client invokes the remote method lookup on the registry stub to obtain the stub for the remote object from the server’s registry. Finally, the client invokes the sayHello method on the remote object’s stub, which causes the following actions to happen:
- The client-side runtime opens a connection to the server using the host and port information in the remote object’s stub and then serializes the call data.
- The server-side runtime accepts the incoming call, dispatches the call to the remote object, and serializes the result (the reply string) to the client.
- The client-side runtime receives, deserializes, and returns the result to the caller.
- The response message returned from the remote invocation on the remote object is then printed to System.out.
RMI provides a solid platform for true object-oriented distributed computing. We can use RMI to connect to Java components or to existing components written in other languages. As Java proves itself in our environment, we can expand our Java use and get all the benefits-no of porting low maintenance costs, and a safe, secure environment. RMI gives us a platform to expand Java into any part of our system in an incremental fashion, adding new Java servers and clients when it makes sense. As we add Java, its full benefits flow through all the Java in our system. RMI makes this easy, secure, and powerful.
This, was all about the RMI Mechanism in JAVA. We hope you found this blog helpful. Don’t forget to like and comment :)