RMIIO

RMIIO is a library which makes it as simple as possible to stream large amounts of data using the RMI framework (or any RPC framework for that matter). Who needs this? Well, if you have ever needed to send a file from an RMI client to an RMI server, you have faced this problem. And, if you did manage to implement a basic solution, it probably threw an OutOfMemoryError the first time someone tried to send a 2GB file. Due to the design of RMI, this common and deceptively simple problem is actually quite difficult to solve in an efficient and robust manner.

The RMI framework makes it very easy to implement remote communication between java programs. It takes a very difficult problem (remote communication) and presents a fairly easy to use solution. However, the RMI framework is designed around sending and receiving groups of objects which are all immediately available in memory. How do you send a file from the client to the server without blowing out memory on the client or the server? The tools and APIs in the standard java runtime do not have any ready solutions to this problem, yet many people have encountered it. Spend a few moments searching through Sun's java forums and you will find many questions and very few useful suggestions (seriously, try the search "rmi send file" for some fun reading). Among the suggestions:

  • Send a File object
  • Send a URL
  • Send an InputStream
  • Send an byte[]

The last is the first suggestion actually approaching usefulness--it solves the first problem but not the second (for more detailed rebuttals read the overview javadocs).

What you really want to do is stream data from the client to the server (you have an InputStream, right?) using a framework which does not really expose a streaming model. The RMIIO library was written to fill in that missing gap in the RMI framework. It provides some very powerful classes which enable a client to stream data to the server using only a few extra lines of code.

RemoteStream Example

How simple? Well, how about some example code (note, examples omit normal exception handling for the sake of brevity). The obvious example, of course, is a simple file upload service. If the client and server were running in the same JVM, you would probably create a server implementation like this:

// A simple local file upload service
public class LocalFileUploadService {
  public void uploadFile(String fileName, InputStream fileData) {
    // ... copy fileData to local storage ...
  }
}

Easy, right? Now, to actually turn this into a remote interface, the fileData type needs to be changed, as an InputStream will not work remotely. Using RMIIO, this implementation becomes:

// A simple remote file upload service
public class RemoteFileUploadService {
  public void uploadFile(String fileName, RemoteInputStream remoteFileData) {
    InputStream fileData = RemoteInputStreamClient.wrap(remoteFileData);
    // ... copy fileData to local storage ...
  }
}

That's it, one extra line on the server to wrap the RMIIO RemoteInputStream as an InputStream (yes, it is confusing that the server uses a method with "client" in the name, but in this situation, the server is acting as the client with respect to the RemoteInputStream). Fine, so the server changes are easy, how does the client create a RemoteInputStream?

// a client call to a RemoteFileUploadService
RemoteFileUploadService service = ...;
InputStream fileData = ...;
RemoteInputStreamServer remoteFileData = new SimpleRemoteInputStream(fileData);
service.uploadFile("MyFile", remoteFileData.export());

And there you have a working client which can stream a file to a remote server (again, note that the standard try/catch/finally blocks necessary in actual production code have been omitted from these examples). By wrapping the InputStream using one of the RMIIO RemoteInputStreamServer implementations and exporting it, the source file data can be streamed to the server using an already established RMI connection.

This example just touches on the powerful functionality provided by the RMIIO library. See the Features section below for more details. The RMIIO library is licensed under the GNU Lesser General Public License and is part of the OpenHMS project.

Getting Started

Features

RemoteStreamExporter

As of RMIIO release 1.1.0, the streaming implementation classes have been abstracted from the RPC framework infrastructure. The exporter package has been added to enable the remote stream implementations to be utilized within any RPC framework. The RemoteStreamExporter class can be implemented to tie the remote stream implementations to whatever RPC mechanism is desired, the default being RMI. There is some proof-of-concept code in the src/corbaExample directory showing CORBA being used as the RPC framework, including a C++ client written using omniORB which consumes a remote stream from a java server. Another feasible example would be integrating RMIIO into the JBoss Remoting framework.

In The News

Some interesting articles about RMIIO: