Java Remote Method Invokation Framework
Topics
1. Java® RMI
(Ref: Just Java® 1.2 Ch 16)
The Java® Remote Method Invokation (RMI) framework provides a simple way for Java® programs to communicate with each other. It allows a client program to call methods that belong to a remote object, which lives on a server located elsewhere on the network. The client program can pass arguments to the methods of the remote object and obtain return values, as seamlessly as invoking a method of a local object.
The operation of a remote method call is as follows. The client program actually calls into a dummy method, called a stub, which resides locally. The stub gets the function arguments, serializes them and then sends them over the network to the server. On the server side, a corresponding bare-bones method (called a skeleton) deserializes the argument objects and passes them onto the real server method. This process is reversed in order to send the result back to the client.
The Interface to the Remote Object
Both the client and the server must agree on a common interface, which describes the methods that are to be invoked on the server. For example:
WeatherIntf.java
// An interface that describes the service we will be accessing remotely.
public interface WeatherIntf extends java.rmi.Remote {
public String getWeather() throws java.rmi.RemoteException;
}
2. The RMI Client
Here is the example code for the client. The call to Naming.lookup() returns a reference to a Remote object that is available on the server (localhost in this case) under the service name /WeatherServer. Before we can access its methods, the Remote object must be cast to the appropriate interface type (WeatherIntf in this case).
RMIdemo.java
import java.rmi.*;
public class RMIdemo {
public static void main(String[] args) {
try {
// Obtain a reference to an object that lives remotely on a server.
// The object is published under the service name WeatherServer and
// it is known to implement interface WeatherIntf. We cast to this
// interface in order to access the object's methods.
Remote robj = Naming.lookup("//localhost/WeatherServer");
WeatherIntf weatherServer = (WeatherIntf)robj;
// Access the services provided by the remote object.
while (true) {
String forecast = weatherServer.getWeather();
System.out.println("The weather will be " + forecast);
Thread.sleep(500);
}
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
3. The RMI Server
Here is the example code for the server. The server makes its services available to the client by registering them with the RMI registry using a call to Naming.rebind(). In this code, the server side object is made available under the name /WeatherServer.
WeatherServer.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
public class WeatherServer extends UnicastRemoteObject implements WeatherIntf {
public WeatherServer() throws java.rmi.RemoteException {
super();
}
// The method that will be invoked by the client.
public String getWeather() throws RemoteException {
return Math.random() > 0.5 ? "sunny" : "rainy";
}
public static void main(String[] args) {
// We need to set a security manager since this is a server.
// This will allow us to customize access priviledges to
// remote clients.
System.setSecurityManager(new RMISecurityManager());
try {
// Create a WeatherServer object and announce its service to the
// registry.
WeatherServer weatherServer = new WeatherServer();
Naming.rebind("/WeatherServer", weatherServer);
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
4. How to Compile and Run
- Compile all three .java files using javac:
javac *.java
- Generate the stub and the skeleton classes for the server:
rmic WeatherServer
- Put the class files in a location that the JDK knows about e.g. the current directory or $JAVAHOME/jre/classes.
- Start the RMI registry:
rmiregistry
- Create a permissions file for the server:
permit
grant {
permission java.net.SocketPermission "*", "connect";
permission java.net.SocketPermission "*", "accept";
// Here is how you could set file permissions:
// permission java.io.FilePermission "/tmp/*", "read";
};
- Start the server using the security policy prescribed by the permissions file:
java -Djava.security.policy=permit WeatherServer
- Start the client:
java RMIdemo
javac *.java
rmic WeatherServer
rmiregistry
permit
grant {
permission java.net.SocketPermission "*", "connect";
permission java.net.SocketPermission "*", "accept";
// Here is how you could set file permissions:
// permission java.io.FilePermission "/tmp/*", "read";
};
java -Djava.security.policy=permit WeatherServer
java RMIdemo
The client will now communicate with the server to find out the current weather.