RMI stands for remote method invocation and, as the name implies, is a protocol for a Java program to invoke a method of an object running on another computer. It provides an API (Application Programming Interface) for exporting an object from one program (called the server) and calling the methods of that object from another program (called the client), possibly running on another computer.
The Java RMI Registry is a key component of the Java RMI system and provides a centralized directory for servers to register services and for clients to search for those services.
Server Interface Announcement
To learn the intricacies of the Java RMI system, let’s implement a simple server object that provides a method to accept a name and return a greeting. Here is the definition of the object’s interface:
import java.rmi.Remote; import java.rmi.RemoteException; public interface Greeting extends Remote { public String greet(String name) throws RemoteException; }
The name of the interface is called Greeting . It provides a single method called greet () that takes a name and returns a suitable greeting.
To mark this interface as exportable, it must extend the interface java.rmi.Remote . In addition, the method must declare a throws clause listing java.rmi.RemoteException in addition to any application-specific exceptions. Exceptions This is to allow client code to handle (or propagate) remote method invocation errors such as host-not-found , connection failure, etc. Д.
Server object implementation
After declaring the interface (which is used by clients), we implement the server-side object and provide the greet () method as shown. A simple format string is used to format the greeting.
public class GreetingObject implements Greeting { private String fmtString = "Hello, %s"; public String greet(String name) { return String.format(this.fmtString, name); } }
The main server method
Let’s now put all these pieces together and implement the main () server method. Let’s walk through each of the relevant steps.
The first step is to create an implementation of the server object.
Greeting greeting = new GreetingObject();
Next, we get a stub for the server object from the RMI runtime environment. The stub implements the same interface as the server object. However, the method implements the necessary communication with the remote server object. This stub is used by the client to transparently call the method on the server object.
Greeting stub = (Greeting)UnicastRemoteObject.exportObject(greeting, 0);
Once a stub is obtained, we pass that stub to the RMI registry to bind to the specified named service. When a client requests an implementation of that service, it receives a stub that knows how to contact the server object. The static LocateRegistry.getRegistry () method is then used to obtain a reference to the local registry. The rebind () method is then used to bind a name to the stub.
String name = "Greeting"; Registry registry = LocateRegistry.getRegistry(port); registry.rebind(name, stub);
The complete main method.
import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; public class Main { static public void main(String[] args) throws Exception { if ( args.length == 0 ) { System.err.println("usage: java Main port#"); System.exit(1); } int index = 0; int port = Integer.parseInt(args[index++]); String name = "Greeting"; Greeting greeting = new GreetingObject(); Greeting stub = (Greeting)UnicastRemoteObject. exportObject(greeting, 0); Registry registry = LocateRegistry.getRegistry(port); registry.rebind(name, stub); System.out.println("Greeting bound to \"" + name + "\""); } }
Building the server
Let’s now look at building the server. For simplicity, we build using the command line in Linux rather than a build tool such as Maven.
The following compiles the source files into class files in the target directory.
rm -rf target mkdir target javac -d target src/server/*.java
Compile the class files into a JAR file for execution.
jar cvf target/rmi-server.jar -C target server
We also assemble the interface files needed to compile the client into a JAR library.
jar cvf target/rmi-lib.jar -C target server/Greeting.class
Client implementation
Let’s now look at the client implementation used to call the methods of the server object.
As with the server, get a reference to the registry by specifying the hostname where the registry is running and the port number.
Registry registry = LocateRegistry.getRegistry(host, port);
Next, we look for the service in the registry. The lookup () method returns a stub that can be used to call the services.
Greeting greeting = (Greeting) registry.lookup(name);
And call the method, passing the necessary arguments. Here we get the greeting by passing the name and printing it.
System.out.println(name + " reported: " + greeting.greet(myName));
The complete client code:
package client; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry.Registry; import server.Greeting; public class Client { static public void main(String[] args) throws Exception { if ( args.length != 3 ) { System.err.println("usage: java Client client host port myName"); System.exit(1); } int index = 0; String host = args[index++]; int port = Integer.parseInt(args[index++]); String myName = args[index++]; String name = "Greeting"; Registry registry = LocateRegistry.getRegistry(host, port); Greeting greeting = (Greeting) registry.lookup(name); System.out.println(name + " reported: " + greeting.greet(myName)); } }
RMI Registry
Now let’s start the server program so it can start serving requests.
java -cp target/rmi-server.jar server.Main 1099 # throws Exception in thread "main" java.rmi.ConnectException: Connection refused to host: xxx; nested exception is: java.net.ConnectException: Connection refused
What is this exception? Connection refused.
The reason you get this exception is this: note that from the server code, it is trying to connect to the local registry on port 1099. In the event of a failure, you will get this exception.
The solution is to run the RMI Registry. The RMI Registry is a program that comes with the Java Virtual Machine and is called rmiregistry . It should be located in the bin directory of the Java Virtual Machine installation. Running it is as simple as:
/usr/lib/jvm/jdk1.8.0_71/bin/rmiregistry
By default, the registry listens on port 1099. To listen on a different port, specify the port number as follows:
/usr/lib/jvm/jdk1.8.0_71/bin/rmiregistry 1100