Remote Method Invocation
Introduction
What is Remote Method Invocation?
Remote method invocation allows objects residing in one JVM execute methods of objects residing in another JVM. The two JVMs can be in the same machine or executing on different machines located in a network. The object executing a remote method does so as if the remote object was present locally (i.e. accessible through the local classpath.
Why RMI?
To understand this a review of the traditional approach to invoking remote methods is warranted:
Traditional method of doing this was by use of Stream Sockets. Stream sockets can be used to pass primitive data types or objects(provided they implement the Serializable interface) between two hosts on a network. Stream sockets always passed data by value. That is copies of objects were passed back and forth to effect communication.
Why RMI?
Now imagine a client server scenario, in which a client wants to update an Account object present on the server. The
client will typically open a connection to the server and request the object by name. The server will then send a copy of this object to the client through an ObjectOutputStream. The client will receive this object, update the object and send the modified object to the server. The server in turn will replace the server object with the new object received from the client.
Why RMI?
If many clients are requesting updates on objects residing on the server, the number of object copies that travel on the network increases proportionally. The point is that since Objects are passed by value, a copy of the object is sent to the requesting client Thus any modification made on the passed object is not reflected on the server unless the modified object is passed back. This increases network traffic and can have serious implications on the network band-width. For more complex operations like querying a database located on the server the performance implications will be extremely high.
Another problem with this approach is that if the address of the server changes, the client needs to know the location of the new server before it can access the object. That is, the objects are not inherently location transparent.
Why RMI? ď Ž
ď Ž
If it were possible for a client to invoke the methods of objects residing on the server with out actually downloading the object, considerable performance improvements can be achieved. Further it were possible for a client to access a remote object regardless of on which server the object actually existed, the objects become location transparent.
Why RMI?
RMI ( and before RMI , RPC or Remote Procedure Calls) achieves precisely this objective.
Remote Method Invocation involves using the various classes and interfaces available in the java.rmi and java.rmi.server packages. These classes and interfaces provide a framework for an application to access objects residing on remote hosts by reference(not value). Once a client obtains a reference to a remote object, it can invoke the methods on these remote objects as if they existed locally. Any modification made to the object through the remote object reference is reflected on the server. Thus copies are never passed over the network.
Stubs & Skeletons
RMI is ideally suited to applications which require a client to an application residing on another machine.
Almost all application servers(servers that run applications as opposed to file servers that serve files or data) can benefit from RMI or a framework that allows RMI. RMI is the distributed component model for JAVA applications. COM/DCOM will be Microsoft’s equivalent. This means one Component(java Object) distributed in a network can be accessed by any other Component on the network.
This is made possible by what are known as client-stubs and server-skeletons.
Stubs & Skeletons
The java.rmi.Remote interface
RMI provides an interface called Remote. This is contained in the java.rmi package.
If a class wants it’s objects to be accessible remotely, that class must implement this interface. Thus we call an object a Remote Object if it is accessible remotely. The Remote interface is an empty interface having no methods. It is a tag interface that tells the Java run time that objects of this class are remotely accessible. To make this class have it’s methods remotely accessible, the methods need to be declared in an interface that extends the Remote interface.
Using the java.rmi.Remote interface
Using the RMI interface ď Ž
The exact steps needed to do this are: 1. 2.
Declare an interface that extends java.rmi.Remote Declare methods that need to be accessed remotely in this ď Ž
3.
All Remote methods must throw java.rmi.RemoteException
Define a class that implements this interface.
1. Extend RMI ď Ž
Declare an interface that extends java.rmi.Remote:
public interface MyInterface extends java.rmi.Remote
2. Declare methods that need to be accessed remotely ď Ž
public interface:
MyInterface extends java.rmi.Remote { //Declare all methods here public String getMessage()throws java.rmi.RemoteException; //More methods }
3. Define a class that implements this interface. Public class MyClass implements MyInterface { //Variable definitions/Declarations //Constructors //Other methods public String getMessage()throws RemoteException { return new String(“Hello there!�); } }
RMI Class Hierarchy
A Sample Case Mortgage Computation via RMI
A Scenario
Betty just got a job in a mortgage company.
Her supervisor Joy asked her to make the mortgage calculator available to the public. That is to say the mortgage calculator will be put on an intranet or the internet. The mortgage calculator is an existing software and installed on an individual computer. If it is installed on the server, it will be easier to maintain and update. This is Betty's first assignment. She felt so excited. She decided to use Java Remote Method Invocation (RMI) technology.
The calculatePayment() Method ď Ž
She was ready to start now. She started to look at the Mortgage calculator class. The key method in the Mortgage class is the calculatePayment() method listed below:
public double calculatePayment(double principal, double annualRate, int years){ double monthlyInterest = annualRate / 12; double monthlyPayment = (principal * monthlyInterest) / (1 - Math.pow(1/ (1 + monthlyInterest), years * 12)); return monthlyPayment; }
The calculatePayment() Method
To calculate the monthly payment for a mortgage, you need three data: principal,
annual rate and term. When a user provided these three data to an application, the monthly payment would be returned.
In order to try new RMI features, she quickly wrote a Mortgage program. She was going to use this command-line program to try the RMI features.
Designing a Remote Interface
Since the calculatePayment() method is a key method in Mortgage class, Betty decided to make this method remotely available (invoked).
If a user provides principal, annual interest rate and loan term from a command-line, the monthly payment information will be printed on the client side.
How to make such method available via network?
According to the RMI technology, you should design a remote interface first and then put the method signature inside the remote interface. Betty checked the new RMI specification, such design step since jdk 1.1 has not been changed.
What is a remote interface? ď Ž
ď Ž
According to RMI specification, a remote interface is an interface that extends java.rmi.Remote interface and declares a set of methods that may be invoked from a remote Java Virtual Machine(JVM). Note that the java.rmi.Remote interface serves as a mark to tell the system that methods declared within this interface may be invoked from a non-local virtual machine.
What is a remote method? A remote method is a method that is declared inside a remote interface. Betty followed the step and designed a remote interface named Payment. She declared the method calculatePayment() signature and made it throw RemoteException which is required.
What is a remote method? import java.rmi.Remote; import java.rmi.RemoteException; public interface Payment extends Remote { public double calculatePayment(double principal, double annualRate, int terms) throws RemoteException; }
More on remote methods
Recall that only method signatures or abstract methods are allowed within an interface, so does the remote interface.
The implementation class will take care of the remote methods.
Right now, we can say that Payment is a remote interface and calculatePayment() is a remote method. You may be wondering why the method must throw RemoteException. Because remote method invocation may fail in many ways, like server down, resources unavailable, the method itself may throw exception, etc. If the failure happens, the client should be able to know it via the RemoteException.
More on remote methods Please note that: The Payment interface must extends java.rmi.Remote interface. It is required. The method signature in the remote interface must throw java.rmi.RemoteException. It is required too. If you want multiple methods available remotely, just put these method signatures inside one or more remote interfaces and let them throw java.rmi.RemoteException. This is the first step you should do when you use RMI technology. Ask yourself if you know how to make a method remotely available, what is the first step? The next step is to design a remote object.
Design a Remote Object ď Ž
According to the RMI specification, a remote object is one whose methods can be invoked from another Java virtual machine, potentially on a different host(JVM).
Design a Remote Object
You have learnt from the previous section how to design a remote interface. Do you remember that you have not implemented the remote method calculatePayment(). The implementation class is a remote object. So
we need to design a class which implements the remote interface Payment and defines the remote method -- calculatePayment().
Design a Remote Object
Betty made the implementation class name PaymentImpl, because it is easily to be recognized when you deal with multiple classes. Since
Payment is an interface, "Impl" means implementation, PaymentImpl is an implementation class of Payment interface. We will adopt such name convention in the following sections.
The Remote Object import java.rmi.RemoteException; public class PaymentImpl implements Payment { public double calculatePayment(double principal, double annRate, int years) throws RemoteException { double monthlyInt = annRate / 12; double monthlyPayment = (principal * monthlyInt) / (1 - Math.pow(1/ (1 + monthlyInt), years * 12)); return format(monthlyPayment, 2); } public double format(double amount, int places) { double temp = amount; temp = temp * Math.pow(10, places); temp = Math.round(temp); temp = temp/Math.pow(10, places); return temp; } }
More on Remote Objects Note that: ď Ž The remote object class must implement remote interface. In this context, it is Payment interface. ď Ž The remote object class can have any other methods not defined in the remote interface, but these methods can only be used locally, not remotely, like format() method in the example.
More on Remote Objects
When you implement a remote method, if the method doesn't throw any exception, the method head can omit the RemoteException. In
this context, we have to throw the RemoteException, because we have not written any contract to guarantee that the parameters are valid before this method being called.
Ask yourself: what is a remote object? Next step, we should create a server which can be used to hold the remote object.
Design an RMI Server When you have a remote object, you need a carrier to hold it for a possible remote invocation. ď Ž That carrier is often called a server. ď Ž
What is an RMI Server? ď Ž
A typical RMI server is an application that creates a number of remote objects, makes references to those remote objects and waits for clients to invoke methods on those remote objects.
What is an RMI Server? ď Ž
ď Ž
In this context, a server is a class. In this class, we need a main method that creates an instance of the remote object, exports the remote object, and then binds that instance to a name in a Java RMI registry. So we list the server jobs as follows: 1. 2. 3.
Create an instance of the remote object Export the remote object Bind the instance to a name in RMI registry
How to create an instance of the remote object We already create a remote object class -PaymentImpl. To instantiate it, just do it like any other class instantiation.
PaymentImpl robj = new PaymentImpl();
Here robj is an instance of the remote object PaymentImpl.
How to export the remote object?
We will use this method: java.rmi.server.UnicastRemoteObject .exportObject(Remote, int);
to export the remote object.
How to export the remote object?
When you export a remote object, you make that object available to accept incoming calls from clients.
The exportObject() method takes 2 parameters, one is an instance of the remote object, the other is TCP port number. Note that the same port number can accept incoming calls for more than one remote objects. The default number for RMI is 1099. If you pass a zero to the method, the default number 1099 is used. Of course, you can use a different number to listen to different remote client calls.
Payment stub = (Payment) UnicastRemoteObject.exportObject(robj, 0);
How to export the remote object?
Note that the exportObject() method will return a stub which is a term used to describe a proxy class. The
stub class is a key to make remote object available for remote invocation. We need to cast it to the remote interface for safe. The second parameter we use "0" that means we are going to use the default TCP port number, which is 1099.
An alternative way to export remote object ď Ž
You can make the server class extend java.rmi.server.UnicastRemoteObject class and use a constructor to export the object and define a port number.
An alternative way to export remote object public class Server extends java.rmi.server.UnicastRemoteObject implements aRemoteInterface{ public Server(int port) { super(port); } .... Naming.bind(uniqueName, this); .... }
What is Java RMI registry The Java RMI registry is a remote object that maps names to remote objects. The methods of LocateRegistry are used to get a registry operating on a particular host or host and port. The method bind() or rebind() binds a unique name to the reference of the remote object.
What is Java RMI registry java.rmi.registry.Registry registry = java.rmi.registry.LocateRegistry.getRegist ry(); registry.bind("Mortgage", stub); or use: registry.rebind("Mortgage", stub);
The Server Class import import import import
java.rmi.registry.Registry; java.rmi.registry.LocateRegistry; java.rmi.RemoteException; java.rmi.server.UnicastRemoteObject;
public class Server { public Server() {} public static void main(String args[]) { try { PaymentImpl robj = new PaymentImpl(); Payment stub = (Payment) UnicastRemoteObject.exportObject(robj, 0); Registry registry = LocateRegistry.getRegistry(); registry.bind("Mortgage", stub); System.out.println("Mortgage Server is ready to listen..."); } catch (Exception e) { System.err.println("Server exception thrown: " + e.toString()); e.printStackTrace(); } } }
Design an RMI Client In the previous sections, we designed a remote interface, a remote object and a server. ď Ž And now we need to design a client to test the functionality of the server. ď Ž
What is an RMI Client? ď Ž
A typical RMI cient is an application that gets a remote reference to one or more remote objects in the server, then invokes methods on these remote objects.
What is an RMI Client?
Remember that we register a remote object by name "Mortgage" with a TCP port number 1099(default). In our client class, we need some code to look up the object by name "Mortgage" and a TCP port number. When we get the stub class from the RMI server, we can use this stub class to call the remote method.
What is an RMI Client? ď Ž
There are two things you should do before calling the remote method: Locate a host from the registry mechanism. 2. Look up the remote object by its name. 1.
How to locate a host? ď Ž
Use the following code to locate a host.
Registry reg = LocateRegistry.getRegistry(hostName); ď Ž
In our example, we will use localhost as the default host. If you run the server in a different computer, you need to give that computer's name as a host name.
How to look up a remote object?
You look up a remote object by its name. So, you must first know the name of the remote object. Remember
that we register the remote object by name "Mortgage" in the server's registry. We use code below to look up "Mortgage" object and get a stub back. The stub can be used to access the remote method. Payment stub = (Payment) reg.lookup("Mortgage");
How to look up a remote object?
Note that the returned remote object reference should be cast back to the remote interface. In this context, we cast to Payment interface. The most beautiful thing is that a method invocation on a remote object has the same syntax as a method invocation on a local object when you get the reference to a remote object.
The Client Class
Note that we use the returned stub from lookup() method to call the remote method calculatePayment() and pass three parameters obtained from the command-line. We have to use try/catch block to locate RMI registry, look up stub class and call the remote method. If
the server has a problem or the remote method has a failure, the client side should be able to know it through the catch clause.
Running the files
Now, you can try the client\server system on your own computer. You
may be wondering how it could be to use one computer to try a client\server system. Remember that, you can start different command-line windows to try it. Because every command-line window will get one distinguished Java Virtual Machine(JVM) instance, and the communication between two JVMs can be established in one computer. We will use localhost as a host for the server.
Running the files Betty checked the RMI specification, found that a new feature for running an RMI server is available. New feature:
You
don't need to generate a stub class before you start the server. The stub class will be generated on the fly if you use jdk 1.5.0 version or above.
Running the files
If you use jdk version below 1.5.0, you cannot run the examples listed here. You must use rmic utility to generate a stub class. If so, use the following command to generate a stub class: set classpath= rmic -v1.2 Server
Running the files
A file with name Server_stub.class is generated for JVM communication. Now you can go to the next step to start rmiregistry and server. You need to follow the steps below to run the server: Start rmiregistry utility 2. Start a server 1.
Running the files Let's start rmiregistry. First make sure the classpath is empty, then use command as follows: C:\*your_directory*\set classpath= C:\*your_directory*\start rmiregistry Note that an empty command-line window will pop-up.
Don't close it, minimize it if you want. That window is for rmiregistry.exe program.
Running the Server
Then, you can start a server window in the following command: C:\myrmi\start java Server The pop-up window will have the following printout which indicates the server is started successfully and ready to accept client connection. Mortgage server is ready to listen... Note that the RMI server we designed is not for one client connection. It can accept many-client connections simultaneously.
Running the Server ď Ž
ď Ž
Then, you can start a server window in the following command: C:\myrmi\start java Server The pop-up window will have the following printout which indicates the server is started successfully and ready to accept client connection. Mortgage server is ready to listen...
Running the Client ď Ž
When the server starts, you are ready to start a client. Please issue the following command: C:\myrmi\java Client
ď Ž
When the client starts, the LocateRegistry.getRegistry("localhost") sends information to the RMI registry which is held by the localhost(the Server command-line window) and asks to look for a remote object named "Mortgage".
Running the Client
Since the server has such remote object, so the server sends an instance of stub class back, or we can say the client downloads the stub class from the localhost server. When the client gets the reference to the remote object, it can use such reference to call remote method calculatePayment() just like to call a local method. This is the most beautiful thing we mentioned earlier for RMI technology.
Running Everything The following shows all commands and printout when you start the RMI server and client system. C:\myrmi>javac -d . Payment.java PaymentImpl.java Server.java Client.java ď Ž
C:\myrmi>set classpath= C:\myrmi>start rmiregistry C:\myrmi>start java Server
Running Everything C:\myrmi>java Client Usage: java Client principal annualInterest years For example: java Client 80000 .065 15 You will get the output like the following: The principal is $80000 The annual interest rate is 6.5% The term is 15 years Your monthly payment is $696.89
Running Everything C:\myrmi>java Client 150000 .060 15 The principal is $150000 The annual interest rate is 6.0% The term is 15 years Your monthly payment is $1265.79 C:\myrmi>
Recap
Process of designing an RMI server and client system 1. 2. 3. 4.
Design a remote interface. Design a remote object. Design an RMI server. Design an RMI client.