Java RMI - Remote Method Invocation: Compiled by G/egziabher T
Java RMI - Remote Method Invocation: Compiled by G/egziabher T
Introduction
Developing Client/Server applications using sockets involves
the design of a protocol that consists of a language agreed
upon by the client and server. The design of protocols is hard
and error-prone. One issue, for example, is deadlock. In a
deadlock, processes never finish executing; these processes
may be holding system resources, preventing other processes
from accessing these resources.
Instead of working directly with Sockets, Client/Server
applications can be developed using Java's Remote Method
Invocation. Java RMI is a package that can be used to build
distributed systems. It allows you to invoke methods on other
Java Virtual Machines (possibly on different hosts).
Java RMI - Remote Method Invocation
A primary goal of RMI is to allow programmers to develop
distributed Java programs
RMI is the Java Distributed Object Model for facilitating
communications among distributed objects
RMI is a higher-level API built on top of sockets
Socket-level programming allows you to pass data through
sockets among computers
RMI enables you not only to pass data among objects on
different systems, but also to invoke methods in a remote
object
The Differences between RMI and Traditional Client/Server Approach
2. The second class acts as a proxy for the remote service and it runs on
the client.
How it works
A client program makes method calls on the proxy object, RMI
sends the request to the remote JVM, and forwards it to the
implementation.
Any return values provided by the implementation are sent back to
the proxy and then to the client's program.
The RMI Server uses the Registry to bind names to remote objects and
register them with the registry. The server can kick-off the RMI registry
when it starts up. Enabling an RMI server application to start the registry
and control access to it gives more control to the developer and also enables
logging of whatever goes on.
Remote Objects are those objects that can be exported and made
available to clients. Clients usually query for a remote object using the
RMI registry directly or using the server thereby getting a reference.
Using this reference, clients then call remote methods. Objects that have
methods that can be called across virtual machines are remote objects.
RMI clients are applications that query the registry for remote objects and
using the reference obtained call remote methods on them for various
services that the remote object provides.
A remote call in RMI is identical to a local call except for the following.
An object passed to a remote method or returned from the method must be
serializable.
The object is passed by value instead of reference (except for references to
remote objects themselves).
A client always refers to a remote object through one of the remote
interfaces that it implements. A remote object can be cast to any of the
interfaces that it implements.
When a reference to a remote object is obtained, the remote object is not sent
over the network to the client requesting it. In its place a proxy object or stub
is sent. This stub is the client side proxy for the remote object. All
interactions by the client will be performed with this stub class. The stub is
responsible for handing off data between the local system and the remote
system. Many clients can hold references to a single remote object. Each
On the server side the skeleton class is responsible for handing off the
method calls and data to the actual object being referenced. This is the server
side proxy for the object being exported.
Layer2: This is the proxy layer, the skeleton and stub layer. The application
deals with this layer directly. All calls to remote methods and marshalling of
parameters and return objects are done through these proxies.
Layer3: This is the remote reference layer. It is responsible for dealing with
the semantics of the remote invocations. This layer is responsible for
handling replicated objects and for performing implementation specific tasks
with remote objects.
Layer4: This is the transport layer. This layer is responsible for actually
setting up connections and handling the transport of data from one machine
to another.
Application Layer
An application that makes available some of its methods to its remote clients
must declare such methods in an interface that extends the java.rmi.Remote
interface. This interface is coded the same way any other interface is coded
with the addition that exception handling must be provided to handle
RemoteExceptions. These are specific to remote calls and can be thrown if a
problem arises in contacting or interacting with a remote application. Once
the methods described in the remote interfaces have been implemented, the
object must be exported. This can be done implicitly if the object extends the
UnicastRemoteObject class or it can be done explicitly with a call to
exportObject () in the package java.rmi.server. Then the application will
register itself with a name server, or registry. This is used to make first
On the client side, the client simply requests a remote object from either a
registry or a remote object that it has already obtained. The reference to the
remote object is cast to one of its Remote interfaces, and any calls to remote
methods can be made directly through this interface.
In RMI's use of the Proxy pattern, the stub class plays the role of the proxy,
and the remote service implementation class plays the role of the RealSubject.
A skeleton is a helper class that is generated for RMI to use. The skeleton
understands how to communicate with the stub across the RMI link. The
skeleton carries on a conversation with the stub; it reads the parameters for
the method call from the link, makes the call to the remote service
implementation object, accepts the return value, and then writes the return
value back to the stub.
In the Java 2 SDK implementation of RMI, the new wire protocol has made
skeleton classes obsolete. RMI uses reflection to make the connection to the
The stub objects use the invoke() method in RemoteRef to forward the method
call. The RemoteRef object understands the invocation semantics for remote
services.
The JDK 1.1 implementation of RMI provides only one way for clients to
connect to remote service implementations: a unicast, point-to-point
connection. Before a client can use a remote service, the remote service must
be instantiated on the server and exported to the RMI system. (If it is the
primary service, it must also be named and registered in the RMI Registry).
The Java 2 SDK implementation of RMI adds a new semantic for the client-
server connection. In this version, RMI supports activatable remote objects.
When a method call is made to the proxy for an activatable object, RMI
determines if the remote service implementation object is dormant. If it is
dormant, RMI will instantiate the object and restore its state from a disk file.
Once an activatable object is in memory, it behaves just like JDK 1.1 remote
service implementation objects.
Transport Layer
The Transport Layer makes the connection between JVMs. All connections
are stream-based network connections that use TCP/IP.
Even if two JVMs are running on the same physical computer, they connect
through their host computer's TCP/IP network protocol stack. (This is why
you must have an operational TCP/IP configuration on your computer to run
Compiled By G/egziabher T. Page 8
the Exercises in this course). The following diagram shows the unfettered
use of TCP/IP connections between JVMs.
On top of TCP/IP, RMI uses a wire level protocol called Java Remote
Method Protocol (JRMP). JRMP is a proprietary, stream-based protocol that
is only partially specified is now in two versions. The first version was
released with the JDK 1.1 version of RMI and required the use of Skeleton
classes on the server. The second version was released with the Java 2 SDK.
It has been optimized for performance and does not require skeleton classes.
(Note that some alternate implementations, such as BEA Weblogic and
NinjaRMI do not use JRMP, but instead use their own wire level protocol.
ObjectSpace's Voyager does recognize JRMP and will interoperate with RMI at
the wire level.) Some other changes with the Java 2 SDK are that RMI
service interfaces are not required to extend from java.rmi.Remote and their
service methods do not necessarily throw RemoteException.
Sun and IBM have jointly worked on the next version of RMI, called RMI-
IIOP, which will be available with Java 2 SDK Version 1.3. The interesting
thing about RMI-IIOP is that instead of using JRMP, it will use the Object
Management Group (OMG) Internet Inter-ORB Protocol, IIOP, to
communicate between clients and servers.
The OMG is a group of more than 800 members that defines a vendor-
neutral, distributed object architecture called Common Object Request
Broker Architecture (CORBA). CORBA Object Request Broker (ORB)
java.rmi.server.RMISocketFactory
UnicastRemoteObject
Unreferenced
The DGC interfaces
The RMI transport layer is designed to make a connection between clients
and server, even in the face of networking obstacles.
While the transport layer prefers to use multiple TCP/IP connections, some
network configurations only allow a single TCP/IP connection between a
client and server (some browsers restrict applets to a single network
connection back to their hosting server).
RMI can use many different directory services, including the Java Naming
and Directory Interface (JNDI). RMI itself includes a simple service called
the RMI Registry, rmiregistry. The RMI Registry runs on each machine that
hosts remote service objects and accepts queries for services, by default on
port 1099.
On the client side, the RMI Registry is accessed through the static class
Naming. It provides the method lookup() that a client uses to query a registry.
The method lookup() accepts a URL that specifies the server host name and
the name of the desired service. The method returns a remote reference to
the service object. The URL takes the form:
rmi://<host_name>
[:<name_service_port>]
/<service_name>
where the host_name is a name recognized on the local area network (LAN) or a DNS name
on the Internet. The name_service_port only needs to be specified only if the naming service
is running on a different port to the default 1099.
In the next sections, you will build a simple RMI system in a step-by-step
fashion. You are encouraged to create a fresh subdirectory on your computer
and create these files as you read the text.
To simplify things, you will use a single directory for the client and server
code. By running the client and the server out of the same directory, you will
Compiled By G/egziabher T. Page 11
not have to set up an HTTP or FTP server to provide the class files. (Details
about how to use HTTP and FTP servers as class file providers will be
covered in the section on Distributing and Installing RMI Software)
Assuming that the RMI system is already designed, you take the following
steps to build a system:
The important thing to note about the interface it that it defines an interface
to the function to be called on the server. In this case, the function to be
called is getWeather(). The client program itself is shown in Figure 2. The
main points of the client program are as follows. First, to implement RMI,
we need to use the java.rmi package. This package contains all the guts to
implement RMI. In the main function, we first instantiate a Remote object of
the type that we want to use. In this case, we are going to remotely connect
to the WeatherServer object through the WeatherIntf interface. Once we
have the object from the server then we can call its functions like we would
as if the object were located on our computer.
Import java.rmi.*;
public class RMIdemo {
public static void main(String[] args) {
try {
Remote robj =
Naming.lookup("//192.168.0.9/WeatherServer");
WeatherIntf weatherserver = (WeatherIntf) robj;
String forecast = weatherserver.getWeather();
System.out.println("The weather will be " + forecast);
Compiled By G/egziabher T. Page 13
} catch (Exception e) {System.out.println(e.getMessage()); }
}
}
Figure 2. The Client Program.
Once the Client and Interface have been written, they have to be compiled
into class files.
4. The Server. It is interesting to note that the Server program also requires
the Interface class as shown in Figure 1. This makes sense since the
Server will be implementing the Interface. To use the Server, we need to
use the java.rmi package and the
java.rmi.server.UnicastRemoteObject package. The Server IS a
UnicastRemoteObject, and is declared as such in the class declaration
shown below. This means that the system will be a remote object that can
be called from a client. Note that the method that we are going to call
from the client is the getWeather() function and it can throw a
RemoteException. The interesting function to see here is the main
function. To implement RMI, we need to set a security manager with
permissions that will allow clients to access functions on this pc from
another pc. This is easily done by setting the System Security Manager to
a RMISecurityManager. This will allow other pcs to call functions on this
pc. Then we create an instance of this class simply so that we can pass
the object as an argument to the Naming.Rebind. Rebind is the way a
server announces its service to the Registry. The Registry is a program
that contains a table of services that can be used on a server by client
programs.
Import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
public class WeatherServer extends UnicastRemoteObject implements
WeatherIntf {
public WeatherServer () throws java.rmi.RemoteException {
super();
}
public String getWeather() throws RemoteException {
return Math.random()>0.5? "sunny" : "rainy";
}
public static void main(String[] args) {
Compiled By G/egziabher T. Page 14
System.setSecurityManager(new RMISecurityManager());
try {
WeatherServer myWeatherServer = new WeatherServer();
Naming.rebind("/WeatherServer", myWeatherServer);
} catch (Exception e) { System.out.println(e.getMessage()); }
}
}
Figure 3. The Server Program.
5. Compiling the code. So far we have created three java programs: the
client, the server and the interface. Each of these must be compiled into
class files. This can be done in the IDE or on the command line by using
javac WeatherIntf.java, javac WeatherServer.java, or javac
RMIdemo.java for example. Once the three class files have been
compiled, we now have to create the stub and the skeleton for the
network communications between them. The is done by using the rmic
compiler and the server program. The following can be entered at the
command prompt: rmic WeatherServer. This will create
WeatherServer_Stub.class and WeatherServer_Skel.class for the
client and server respectively.
6. Running the Program. The Server needs the skeleton, the interface and
the server program class files. The Client needs the Stub, the interface
and the client program class files. The best place to put these files is in
the Java Runtime Environment directory. On my machine it is:
C:\Program Files\JavaSoft\JRE\1.3\lib\ext. On the Server side we need to
start the registry so that the server functions can be made public to other
machines. This is done by starting the rmi registry via typing at the
command prompt: rmiregistry. The registry program will continue to
run in this window until CTRL-C is pressed. To run the server with the
RMISecurityManager, we have to define the permissions that we want to
grant clients. We do this via a permit file. The permit file that I used is
shown in Figure 4. Basically, I set connect and accept permissions on the
socket connections. I also set read permissions on files in the tmp
directory just to illustrate, although it is not required in this demo.
Grant {
permission java.net.SocketPermission "*", "connect";
Compiled By G/egziabher T. Page 15
permission java.net.SocketPermission "*', "accept";
permission java.io.FilePermission "/tmp/*", "read";
};
Figure 4. The permit file.
Now we can start the server and make it use the permit file by typing the
following at the command prompt: java Djava.security.policy=permit
WeatherServer
The Client can then be started on the client machine by typing the following
at its command prompt: java RMIdemo
7. Some things to note. Note that all that is needed on the Client side is the
main client program, and the stub (WeatherIntf_stub). The Server side
requires that rmiregistry is running, the main server program is started with
the permit file, and the skeleton (WeatherIntf_skeleton).
Example2:
The following lab work shows you how create a Java RMI application,
which perform the calculation of two numbers.
To create a RMI application, the first step is to design an interface. Use
the notepad
program, create the following Java program and save it as Calculator.java .
___________________________________________________________
public interface Calculator
extends java.rmi.Remote {
public long add(long a, long b)
throws java.rmi.RemoteException;
public long sub(long a, long b)
throws java.rmi.RemoteException;
public long mul(long a, long b)
throws java.rmi.RemoteException;
public long div(long a, long b)
throws java.rmi.RemoteException;
}
__________________________________________________________
The second step is to implement the interface. Create the following Java
program and save it as CalculatorImpl.java.
___________________________________________________________
public class CalculatorImpl extends
CalculatorImpl_Skel.class
Next, create a RMI server. Create the following Java program and save it
as
“CalculatorServer.java.
__________________________________________________________
import java.rmi.Naming;
public class CalculatorServer {
public CalculatorServer() {
try {
Calculator c = new CalculatorImpl();
Compiled By G/egziabher T. Page 17
Naming.rebind("rmi://localhost:1099/CalculatorService", c);
} catch (Exception e) {
System.out.println("Trouble: " + e);
}
}
public static void main(String args[]) {
new CalculatorServer();
}
}
__________________________________________________________
Finally, create a RMI client. Type in the following Java program and save
it as
“CalculatorClient.java.
__________________________________________________________
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
So far, the client and server programs are all running on the same
computer, although they are running through networking services. Next, is to
run the client and server programs on different computers connected by real
networks.
.
Exercise 2:
Compiled By G/egziabher T. Page 19
Base on above exercises, design Any type of application such that RMI
Lottery application. Each time you run the client program -- java
LotteryClient n, the server program LotteryServer will generate n set of
Lottery numbers. Here n is a positive integer, representing the money you
will spend on Lottery in sterling pounds. You should write this program in a
proper engineering manner, i.e. there should be specifications, design (flow
chart, FD, or pseudo code), coding, test/debug, and documentation.
Reading Assignment: