Saturday, 3 August 2013

Working of Java RMI And Serialization

Please go through Java RMI Basics before reading this topic.

How does RMI works?

RMI (Remote Method Invocation): RMI enables us to call a Remote java API as if it is a local method and we gets the results. EJBs (Enterprise Java Beans) were primarily built using RMI. Here is what happens behind the scene when you invoke a remote API. RMI requires communication across the network for executing an API on a remote server machine. The remote method invocation is done by using RMI Stub at client side and RMI server handling at server (replacing the earlier version of RMI Skeleton).

Working of RMI
Working of RMI

RMI Stub is generated from the Remote API class using RMI compilation (rmic utility comes with JDK). A remote API requires to implement a Remote interface (Interface extending java.rmi.Remote) for the JVM to identify that this API can be invoked remotely. The Remote API need to extend java.rmi.UnicastRemote for making use of export method in the default constructor and make the Remote Object available to accept client connections by listening on a TCP port.

The Remote API needs to be registered in RMI Registry for making it available for the client access. When then Remote API is registered in the RMI registry, the Remote API Stub object is loaded into the RMI Registry and made available for client invocations. The Remote API does not leave its JVM and it is the stub object that the client receives on lookup.

RMI client access the Remote API via RMI Stub. So, the RMI client needs to have RMI Stub and Remote Interface in the class path. The Remote Interface needs to be there at the client side for the client application to have reference to the Remote API.

Java don't require to generate a skeleton class any more for server side parsing of the RMI client message from Java 1.2. A skeleton for a remote object is a JRMP protocol server-side entity that has a method that dispatches calls to the actual remote object implementation. A sub protocol is introduced that eliminates the need for skeletons.

The client java program performs a lookup in RMI registry to get the RMI Stub of the actual server side implementation. The client side Application makes call to the Remote API via Stub and Stub makes a network socket connection to the server and converts the API invocation data into a byte stream along with relevant method parameters and passes on this information in byte stream.The server side RMI container will listen to such messages sent to the RMI port and passes it on to the RMI Server.

The RMI Server will receive this byte stream information, reconstruct java Objects and uses it to invoke the required Java API implementation. The return value will again go to the Server and get converted into byte stream and RMI container returns it to the client side Stub. The client side Stub reconstruct the return value to the java object and returns to the calling java program.

Need for Serialization

While discussing RMI, we had seen the necessity of sending java objects across the network as byte streams and reconstructing them back as java objects. Here comes the requirement for serialization.

The purpose of serialization in Java is to support transfer an object from one JVM to another. This is done by converting java objects into byte stream so that it can be transported through the network via socket or stored in a file or repository. The transported or stored stream is de-serialized back to java object at the target JVM. In use cases where we have heavy complex object, the byte stream can be written into a database and read back when we require the data to be displayed again.

Steps for making a class serializable

1. Implement Serializable interface: This is an empty interface and have no definitions. This is a marker interface and just tells JVM that this class can be serialized. An instance of a Serializable java object can be written into an ObjectOutputStream for transporting across network or for storing and while deserialization, the stream is taken as ObjectInputStream and read back to Object.

2. All instance variables used in the Serializable class or it's super class should also be Serializable: We may end up having a variable with an inbuilt data type with variables that are not Serializable. For example, elementData of ArrayList.
If the data is not important in the new JVM, we can declare this variable as transient. Transient variables are not considered during serialization.
If the data is important to us, then the ideal solution is to implement custom serialization deserialization logic using writeObject and readObject methods respectively. The JVM will invoke these methods instead of the default methods for serialization.

3. Override equals() and hashCode() if necessary: Suppose if we are making a deep copy of the java object using serialization, the default equals() method would return false as it compare the reference of the java objects but they are the copy of same objects. In such cases, we may require to override equals() and hashCode() methods.

Serial Version UID and its significance

What happens if the class definition of the JVM is old from the current version of the serializable object? What if a new property is added to the Serializable object and the remote JVM does not know about it?
When the class is serialized, the serial version UID is serialized along with other contents. The JVM which deserializes the object compares the serial version UID of loaded class with that in the content.
If they do not match, then InvalidClassException is thrown.
In such scenarios, the more desirable behaviour is to ignore the value of the newly added variable for backward compatibility. For achieving this, we can declare the serial version UID ourselves. This means the logic of JVM will not be used for generating the serial version UID. If the serial version UID of two class definitions are same, there won't be any exception thrown and the newly added variable will have the default value.

For creating a sample RMI Application, please go through Java RMI Basics

Friday, 2 August 2013

Java RMI Basics With Example

Remote Method Invocation (RMI)

RMI is a mechanism to create a distributed application or a multi-tiered application in Java. RMI allows an object to access Remote APIs in a separate server there by allowing the application to be split into separate tiers like web tier, business tier, persistence tier etc.
The details of working of RMI is covered at Working of Java RMI And Serialization
You can go through Working of Java RMI after finishing this chapter.

How to write a simple RMI application

Following are the steps for developing a simple RMI program:

(1) Create an interface for your API to be invoked remotely, extend it with java.rmi.Remote

The interface of the API that needs to be invoked should extend java.rmi.Remote for the JVM to identify itself as an interface whose methods can be invoked from another JVM.
A sample interface is given below:

package com.prasune.rmi;

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface TestRemote extends Remote {

      public String execute(String message) throws RemoteException;

(2) Implement your Remote API and extend it with java.rmi.server.UnicastRemoteObject

We are extending Remote API Implementation with java.rmi.server.UnicastRemoteObject to make use of its constructors that export the object. Exporting a remote object makes it available for client calls by listening on a TCP port.
The exportObject method returns a Remote stub object of the acual implementation and the Remote API implementation remains in the JVM in which it was created.

package com.prasune.rmi;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class TestRemoteImpl extends UnicastRemoteObject implements TestRemote {

      public TestRemoteImpl() throws RemoteException {

      public String execute(String message) throws RemoteException {
            System.out.println("Received message: " + message);
            return "Invoked remote method successfully";

(3) Create a RMI server class to register the remote implementation in RMI Registry

This is a class for registering the Remote API Implementation in RMI Registry so that the export method of UnicastRemoteObject makes the API available for incoming RMI client invocations.

package com.prasune.rmi.server;

import java.rmi.Naming;
import java.rmi.RemoteException;

import com.prasune.rmi.TestRemote;
import com.prasune.rmi.TestRemoteImpl;

public class TestRMIServer {

      public static void start() throws RemoteException, MalformedURLException {
            TestRemote test = new TestRemoteImpl();
            Naming.rebind("rmi://localhost:1099/TestRemoteService", test);

      public static void main(String[] args) throws RemoteException,
                  MalformedURLException {

(4) Create a RMI Client class in a separate java project, which does the look up of the remote object and access the remote API via stub. You need to copy Remote interface to the class path or copy the Remote Interface source file.

The RMI client code looks up the RMI Registry to get the Remote Object Stub registered by the server. This returns RMI stub of the implementation. The RMI client application invokes the Remote API on the stub of actual implementation.

package com.prasune.rmi.client;

import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;

import com.prasune.rmi.TestRemote;

public class TestRMIClient {

      public static void main(String[] args) throws MalformedURLException, RemoteException, NotBoundException {
          TestRemote test = 
(TestRemote) Naming.lookup("rmi://localhost:1099/TestRemoteService");
            System.out.println(test.execute("RMI invocation"));

(5) Compile the all the files (will happen by default if you are using an IDE)

(6) Generate Stub class by using rmic command:

You will have rmic utility in your JDK/bin.
Go to command prompt.
Got to directory in which class files are generated.
execute rmic.exe com.test.rmi.TestRemoteImpl from this location.
This will generate TestRemoteImpl_Stub.class

(7) Start the RMI Registry

You will have the RMI registry in your JDK/bin which you can make use of. The default port of RMI Registry is 1099, you can start on a port of your choice by specifying the port in rmic command. In that case, the binding URL needs to be changed accordingly.

(8) Run the Server side class

Once the registry is started, you can start the server. The RMI registry needs to know the RMI server code base to download and register RMI stub in its registry. So, if you run the RMI Server program now, you may get ClassNotFound exception for the RMI stub.

To handle this problem, set the java.rmi.server.codebase property. The property requires that a directory path be terminated with a forward slash.

(9) Copy the generated stub to client project class path and Run the Client side class(at another JVM)
The remote object we gets via lookup is the object of the stub class and the remote object is invoked through this stub like a local method.

The server JVM will show a print of "Received message <message you pass as parameter>".
The client JVM will show a print saying "Invoked remote method succesfully".

Now, you can go through the details of working of RMI is covered at Working of Java RMI And Serialization