The Java Remote Method Invocation (Java RMI) is a Java API that performs the object-oriented equivalent of remote procedure calls (RPC), with support for direct transfer of serialized Java classes and distributed garbage collection.
The original implementation depends on Java Virtual Machine (JVM) class representation mechanisms and it thus only supports making calls from one JVM to another. The protocol underlying this Java-only implementation is known as Java Remote Method Protocol (JRMP).
In order to support code running in a non-JVM context, a CORBA version was later developed.
Usage of the term RMI may denote solely the programming interface or may signify both the API and JRMP, whereas the term RMI-IIOP (read: RMI over IIOP) denotes the RMI interface delegating most of the functionality to the supporting CORBA implementation.
and if you do not understand, looking one step up, java rmi is actually a java implementation of remote procedure call (rpc). Excerpts from wikipedia.
In computer science, a remote procedure call (RPC) is an inter-process communication that allows a computer program to cause a subroutine or procedure to execute in another address space (commonly on another computer on a shared network) without the programmer explicitly coding the details for this remote interaction.[1] That is, the programmer writes essentially the same code whether the subroutine is local to the executing program, or remote. When the software in question uses object-oriented principles, RPC is called remote invocation or remote method invocation.
Okay, enough of the theory, let's start a simple java rmi using tomcat. This learning tutorial assume you have tomcat server running and know basic how to deploy the jar file into your tomcat running server.
Provide access permission to the jar. Probably easiest if you are starting up to learn this and too much concept to grasp for, you start with grant permission for all security and when you are good at it, start to fine tune. You should set this in <TOMCAT_HOME>/conf/catalina.policy
grant {
permission java.security.AllPermission;
};
Then now we will code at the server side. First, let's create a java interface which the server will implement this and the client will invoke this method remotely.
import java.rmi.Remote;
public interface CalculatorInterface extends Remote {
public final String serviceName = "MyRemoteService";
public Double Add(Double num1, Double num2) throws Exception;
public Double Sub(Double num1, Double num2) throws Exception;
public Double Mul(Double num1, Double num2) throws Exception;
public Double Div(Double num1, Double num2) throws Exception;
public Integer Factorial(Integer num) throws Exception;
public Float Random() throws Exception;
}
So we have an interface of Calculator which extends Remote interface. There are a few public method are exposed in this interface which will be invoke by client later.
public class Calculator implements CalculatorInterface {
public Calculator() {
super();
}
@Override
public Double Add(Double num1, Double num2) throws Exception {
return num1 + num2;
}
@Override
public Double Sub(Double num1, Double num2) throws Exception {
return num1 - num2;
}
@Override
public Double Mul(Double num1, Double num2) throws Exception {
return num1 * num2;
}
@Override
public Double Div(Double num1, Double num2) throws Exception {
return num1 / num2;
}
@Override
public Integer Factorial(Integer num) throws Exception {
Integer t = 1;
for(int i = 1; i <= num;i++){
t = t * i;
}
return t;
}
@Override
public Float Random() throws Exception {
return (float) Math.random();
}
}
Here, we implement the calculator. As seen here, all basic mathematics formulae. Now, we will start this instance in tomcat. The easy way would probably be implement servletContextListener and start the stub on a port when tomcat is starting. With that said, let's read the code below.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class InitCalculator implements ServletContextListener {
public static boolean isRegistered = false;
public static CalculatorInterface service;
public InitCalculator() {
if (!isRegistered) {
try {
service = new Calculator();
CalculatorInterface stub = (CalculatorInterface)UnicastRemoteObject.exportObject(service, 0);
Registry registry = LocateRegistry.createRegistry(9345);
registry.rebind(CalculatorInterface.serviceName, stub);
System.out.println("Remote service bound");
isRegistered = true;
} catch (Exception e) {
System.err.println("Remote service exception:");
e.printStackTrace();
}
}
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void contextInitialized(ServletContextEvent arg0) {
new InitCalculator();
System.out.println("started ...");
}
}
As seen above, when webapp context is initialized, a new object InitCalculator() is created. This object is bind to port 9345, so make sure your firewall allow this as later you will need to access this port remotely. So we create a registray and bind it to the registry on port 9345. So very easy code. Remember to register this listener class into tomcat web descriptor.
<listener>
<listener-class>com.example.InitCalculator</listener-class>
</listener>
Moving on to the last piece of puzzle, the client code.
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class CalculatorClient {
public static void main(String[] args) {
try {
Registry registry = LocateRegistry.getRegistry("localhost", 9345);
String[] names = registry.list();
for (String name: names) {
System.out.println("~~~~~" + name + "~~~");
}
CalculatorInterface serv = (CalculatorInterface)registry.lookup(CalculatorInterface.serviceName);
System.out.println("add total " + serv.Add(1d, 1d));
} catch (Exception e) {
e.printStackTrace();
}
}
}
As can be read above, the client code connect to localhost on port 9345 and then list what's in the registry. Then the interface is created with registry lookup on the interface service name. Now, we can invoke the server method.. Pretty cool stuff. :) See below.
[user@localhost ~]$ java -cp /var/lib/tomcat/webapps/example/WEB-INF/lib/example.jar:. CalculatorClient
~~~~~MyRemoteService~~~
add total 2.0
That's it.