An Overview of Distributed Object Technologies:

RMI, JINI, and CORBA

   Author: Marlon Pierce
    version 0.1

I. Foreword

This is intended to primarily be an overview and appraisal of Sun's contributions to the distributed component world (RMI and Jini), with references and comparisons to the Object Management Group's CORBA specification.  We also make references to WebFlow, a CORBA-based distributed component system developed at Syracuse that we are currently using in the Gateway project.  It is my purpose to provide both a general overview of RMI and Jini, and also discuss their suitability for incorporation into the next generation of WebFlow.  Hopefully by reading this, you can pick up the RMI and Jini buzzwords and go to the references at the end of the report for detailed information.  If you have any questions or comments, please contact me at pierceme@asc.hpc.mil.
 

II. Remote Method Invocation

A. RMI Basics

RMI is essentially a way for making Java interfaces remote, so that client code can implement an interface in which the code actually exists and is executed by another Virtual Machine, usually on another host (the server).  RMI provides a standard, high level way of creating a distributed object architecture over socket connections.   Using a standard RMI compiler (rmic), a developer needs only to
define an interface and the implementation code for class methods.  The RMI compiler generates all of the boilerplate code (called the stub) necessary to handle the remote socket connections.

The key parts of an RMI implementation are the following:

B. Advanced RMI

1. Serving Remote Stubs:  As I glossily put it above, the client code must get the stub class somehow.  Prosaically, we can just publish the stub on the web somewhere and tell interested users to do an ftp or http download of the stub in order to user our RMI services.  But this is Java, so as you should expect, there is also a way to dynamically get the stubs to the clients.  This is done on the server side by setting the system property java.rmi.server.codebase to something like http://mywebserver:8080.  The property can be set either within the server code, or else with the -D option on the command line when the server is started.  Obviously, there must also be a web server running to serve up the class stubs.   Sun includes a simple class server with the RMI distribution.  On the client side, the stub can be downloaded at runtime by providing the appropriate URL to the Naming.lookup() method.

2. Arguments and Return Values: In an RMI application, there can be three types of parameters that can be exchanged between the client and server:

Non-remote objects are passed between client and server using Java's object serialization.  The transfer of the serialized object (recall this
contains both state and class information) between the client and server is called marshaling.

3. Dynamic Class Loading and Behavioral Transfer:  One of the major differences between RMI and CORBA (at least, standard CORBA 2.1) is that RMI supports behavioral transfer.  Without going into the details, this basically means that by doing tricks with java interfaces, the remote server can perform operations that are determined at runtime.  This is similar to the "Command" design pattern.

4. Firewalls:  As of Java SDK 1.2 and higher, all RMI classes are firewall ready, at least for SOCKS and HTTP proxy firewalls.  RMI applications can be configured for firewalls by setting various system properties, which can be done at run time with the -D option.
Probably, in practice this will take a lot of experimentation to get to work for HTTP proxy firewalls.  And of course this does not
address any of the problems that Kerberos has with firewalls.

5. SSL+RMI: Java 2 provides a standard extension for doing SSL encryption, and SSL versions of the Java socket class are available.
Java sockets and server sockets make use of the Factory pattern, and by extending the RMIServerSocketFactory and RMIClientSocketFactory classes, we can transform our implementation file so that it is delivered over an SSL channel.  Interestingly,
we would not need to change our client and server code, just the implementation file.  The reason is that when we call the UnicastRemoteObject's exportObject() method in the implementation file, we specify here that we wish to use SSL sockets.

6. Activatable Objects: As of SDK 1.2, RMI objects can exported as activatable.  This means that if a client connects to a server and downloads the stub, and the server crashes or otherwise becomes unavailable temporarily, then the state of the remote object is restored when the server comes back up, and the client need not be restarted.   Activatable objects need to use the RMID support service provided by Sun.  This daemon can restore all JVMs and server objects on the machine running it.
 

III. JINI

A. Jini Core Concepts

Usually, Jini is presented as a technology for coupling together a wide assortment of computers and intelligent devices such as networked printers and digital cameras and so on.  We don't have to wait for these technologies to find their markets, however, to take advantage of Jini.  Objects are free, so we will take the point of view here that Jini really is designed for networking  systems of distributed components.

Jini is complimentary to, not a replacement for, RMI or CORBA, filling in some of the capabilities glossed over in more traditional client-server systems.  These capabilities include the following:

The following are the principal services that the Jini developers sought to provide to a distributed system: We'll now take a look into each of these in some more detail.

C. Discovery and Join

For a class to make use of Jini services, it must first find at least one running lookup service.  This process is called discovery.  Really, it is just a lookup of lookup services.

Jini defines two fundamental units of organization for a collection of objects (clients and services).  These are groups and federations.  Groups can be defined by any convenient boundary, such as a company department.   Federations are somewhat more interesting.  These are spontaneous communities that can form between clients and services and are especially relevant to intelligent agent systems.  Presumably federations can themselves form larger federations and so on.  The ideas of groups and federations acknowledge the fact that a client will typically not want to look up a particular service from among every possible service provider in the world, but really from its neighborhood first, and then to nearby neighborhoods, and so on.

Jini clients and services are designed to be loosely coupled.  They must publish their existence to a look up service.  The complimentary action is known as discovery, in which the interested client contacts the look up service to find which services it has published.  When the client has successfully contacted a lookup service, it gains a reference called a registrar.  This is a local Java object that must be instantiated in the client code, and is a member of the ServiceRegistrar class.  Sun distributes a lookup service implementation with Jini
called reggie, but presumably you could write your own.  Reggie uses RMI to deliver proxy classes, so it is RMI-dependent even if the discovery process is RMI-independent.

You have basically two discovery protocols to use in your Jini applications.  These have nice java classes/interfaces that hide a lot of the low level details. The two discovery methods are

After discovering a lookup service, the client or service must then join the community associated with the lookup.  With the latest version of Jini there is a new class called JoinManager that standardizes this procedure.   You can still write your own custom join code, though.

D. Lookup Services

Once an object has discovered and joined a particular jini community (centered around one or more lookup services) it then uses those lookup services to interact with the other members.  But what exactly is it that you get when you lookup a service?  Jini services are delivered to clients as downloadable proxies.  This is mobile code.  The proxy is used to create an entirely new object within the client's VM.  This object may be local, an RMI stub, or a stub from CORBA.  Interesting, Jini lookup services store entire (serialized) objects of any sort.  By comparison, the RMI Registry itself only stores RMI stubs.  The client uses the lookup service as a library to check out services.  The client may check out the service entire, or it may get a stub that allows the service's methods to be invoked remotely.  Jini does not care.

E. Leasing

Once a client has checked out a service from the lookup service, there is a relationship established between the client and the service, and all of the problems of networked applications begin.  To lessen the impact of this, Jini introduces the concept of service leases, which means that a client only checks out the service for a specified amount of time.  After the time expires, the service discontinues trying to communicate with the client.  So if that client had died during the application, the service will eventually free up the resources associated with that client interaction.

Many leasing options are available.  Leasers can deny services, clients can renew leases, or they can be canceled early if no longer needed.  On a bit more complicated note, these leases can be handled through third parties.  That is, an intermediary can check out a service on my behalf, as me.

F. Remote Events

As one might imagine, the process of sending events around a distributed system has many problems:

A crucial feature of Jini event listeners is that the RemoteEventListener interface implements the java.rmi.Remote interface.  RMI must be used by Jini events.  This breaks the protocol independence of Jini.

Unlike the standard Java event model, which defines a plethora of event types, all Jini events implement the same interface.  There is only one type of event: remote.  Jini events can be delegated to third parties.  The idea is that you write third party event handlers to take care of the quality of delivery needs of each client.  This is custom code, rather than a standard set of interfaces.  So I could have one delegate called Mailbox that freeze dries all of the events generated while an interested listener is detached from the system.  I could have another delegate (Telemarketer) that keeps trying and trying to reach the registered listener until a connection is made or the appropriate lease expires.

G. Transactions

Transactions group related operations into a composite operation with a boolean condition (success or failure) that depends on the outcomes of the component pieces.  For example, a transaction that debits one account and credits another should be grouped into a single composite operation.  If the debit operation is successful, but the credit operation fails, the entire operation should be voided and no data should be changed.

The Sun distribution comes with an implementation of a transaction manager that is called mahalo.

H. Comparison with CORBA and WebFlow

Most of the key RMI concepts have corresponding pieces in the CORBA specification.  CORBA is of course language independent,  so the remote interfaces are written in the Interface Definition Language (IDL).  A CORBA application is typically broken into the same parts as the RMI application.  Stubs (and skeletons) are generated with a special compiler (vendor supplied) from the IDL.  Both clients and servers create instances of an Object Request Broker object that makes the implementation object remotely deliverable.  The server also must instantiate an object adapter (BOA or, now, POA).  CORBA servers publish references to themselves as strings called Interoperable Object References (IORs) that must be found by the client (such as by a URL address).  The IOR contains all the information necessary for the client and server to connect.

Going beyond the core specification, CORBA provides supplementary specifications for so-called CORBAservices, which vendors may optionally provide.  One of the most commonly available is the naming service, which eliminates the need to look up the IOR and allows the client to look up objects by handles.  Typically, CORBA vendors provide core CORBA and common services like Naming for free, but charge for other services like security.

Note with WebFlow we have (in effect) our own naming service. The client must find the master server by getting its IOR, but once this is done, the client can connect to any available slaves belonging to that master.  In practice, this has some long term disadvantages, since we have introduced custom code perhaps unnecessarily, when we could get more reliable, thoroughly tested code from a vendor.  And it also takes us down a divergent path from the rest of the world.

The activatable objects of RMI are not, to my knowledge, analogous to anything in CORBA.  We certainly don't have anything like this capability in WebFlow.

CORBA is just now (2.3) to the point that it can pass objects and parameters by value (that is, create local copies).  In earlier versions of CORBA, it is not possible to have more than fairly primitive return types and arguments (ints, floats, strings, structs,...) unless these are also IDL interfaces (that is, also remote objects).  I presume this is required for compatibility with C and other older languages.  RMI does not have this restriction.

CORBA allows for dynamic method invocation:  objects can be discovered by servers at runtime, and their methods can be invoked.  In CORBA parlance, this is called introspection.  WebFlow uses this to (for example) dynamically add contexts and modules to the master server.  The master will not know what slaves it will have added to it, what modules these slaves will use and so forth.  This is quite sexy for C code, but Java already comes with this capability (reflection).

CORBA is a specification produced by a consortium of 800+ vendors, and, in my opinion, it often shows.  CORBA must be all things to all people in all languages, whereas RMI is limited to a single language.  For internal development consistency, RMI appears to be relatively straightforward to use for experienced Java programmers, and many of the more sophisticated features are much better hidden under the hood for application developers than in CORBA.   It is worth noting that while the CORBA specification comes with the weight of the OMG behind it (including IBM, HP, Oracle, and even Sun), it appears to me that most of the actual implementations have been done by relatively small vendors.

I.  Observations and Conclusions

It was originally my intention to just review Jini, but as I began reading it became apparent that it and RMI are too closely tied together.  While it appears possible to combine CORBA and Jini, you can't take advantage of all the features.  The problems appear to be as follows: Some other comments:

IV. References