Wednesday 27 April 2011

Handling legacy RMI using Spring remoting

For a POC, I had to work with an external system (J/XFS Device Services) which used RMI as the communication mechanism where exporting and consuming RMI services seemed little slumbering. Since Spring remoting handles it quite good, I used it to get the stuff done quickly. I have given a stripped-down version here as a simple example for RMI using Spring remoting.

The following interface InputDevice is the service interface which the clients will have access to. This is the interface which supposed to extend Remote interface in the conventional RMI implementation either directly or indirectly. It is a very simple interface here with the overhead left to Spring.

InputDevice.java

public interface InputDevice {



 public boolean open();

 

 public byte[] read();

 

 public boolean close();

 

}

A simple implementation of this InputDevice is a Scanner which is given below. This is actually the implementation which would provide the required functionality to the client which would invoke the methods in InputDevice.

Scanner.java

public class Scanner implements InputDevice {



 @Override

 public boolean open() {

  // code which opens the scannner

  return true;

 }



 @Override

 public byte[] read() {

  // code which scans the data. Only dummy data now :-(

  String message = "SCANNED_DATA_DUMMY_" + System.currentTimeMillis();

  return message.getBytes();

 }



 @Override

 public boolean close() {

  // code which closes the scanner

  return true;

 }



}


Having the remote service interface and an implementation ready, now let's focus on how to export this service through RMI. The following DeviceServer class uses the RmiServiceExporter to export the InputDevice service.

The main method in this class can be executed which would export the service at port 54321 in the localhost and ready to serve the requests.

DeviceServer.java

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.rmi.RemoteException;



import org.springframework.remoting.rmi.RmiServiceExporter;



public class DeviceServer {



 public static void main(String[] args) {

  try {

   RmiServiceExporter serviceExporter = exportService();

   System.out.println("Server started. Enter stop to stop it.");

   BufferedReader reader = (new BufferedReader(new InputStreamReader(

     System.in)));

   while (!"stop".equalsIgnoreCase(reader.readLine()))

    ;

   serviceExporter.destroy();

  } catch (IOException e) {

   throw new RuntimeException(e.getCause());

  }

 }



 private static RmiServiceExporter exportService() throws RemoteException {

  RmiServiceExporter serviceExporter = new RmiServiceExporter();

  serviceExporter.setServiceInterface(InputDevice.class);

  serviceExporter.setService(new Scanner());

  serviceExporter.setServiceName("ScannerService");

  serviceExporter.setRegistryPort(54321);

  serviceExporter.afterPropertiesSet();

  return serviceExporter;

 }

}

This simple server would run until stop is entered.

The following simple client consumes the InputDevice service through RMI. It uses RmiProxyFactoryBean to consume the service. Here is the code which can be run to see it consume the service.

DeviceClient.java

import org.springframework.remoting.rmi.RmiProxyFactoryBean;



public class DeviceClient {



 public static void main(String[] args) {

  InputDevice inputDevice = getInputDevice();

  boolean opened = inputDevice.open();

  if (opened) {

   byte[] data = inputDevice.read();

   System.out.println("Data read:" + new String(data));

   inputDevice.close();

  }

 }



 private static InputDevice getInputDevice() {

  RmiProxyFactoryBean proxyFactory = new RmiProxyFactoryBean();

  proxyFactory.setCacheStub(false);

  proxyFactory.setServiceInterface(InputDevice.class);

  proxyFactory.setServiceUrl("rmi://127.0.0.1:54321/ScannerService");

  proxyFactory.afterPropertiesSet();

  InputDevice inputDevice = (InputDevice) proxyFactory.getObject();

  return inputDevice;

 }

}

Using Spring bean configuration, the same could be achived configuring the RmiServiceExporter and RmiProxyFactoryBean beans.


No comments:

Post a Comment