RMI , IIOP, and EJB: A White Paper by Dave Curtis

When Java first met CORBA, the outcome proved advantageous for both communities. The OMG/CORBA community pounced on Java as a cleaner, more tractable, and, ultimately, more cost-effective way to build many more CORBA applications than C++; it offered Java programmers a robust distributed object infrastructure that leveraged battle-tested investments in CORBA technology and a clean way to exploit non-Java legacy assets.

Simultaneously, RMI (Remote Method Invocation) was emerging as a way to build distributed object systems in pure, native Java. Architecturally, RMI is similar to CORBA: It makes remote invocations on objects through established interfaces, using automatically generated proxies and skeletons to manage the marshaling and communication transparently.

In other details, RMI is quite different: it uses Java's native type system to describe remote interfaces and their parameters, whereas CORBA uses a programming­language-independent IDL (Interface Definition Language). A Java/RMI programmer identifies an interface intended for remote access by defining the interface as an extension of the appropriate remote base interface. Remote methods can take parameters of virtually any Java class (specifically, it must be serializable). In contrast, CORBA operations had a more limited palette of data types. Because it was inherently cross-language, any CORBA-defined data type must have had an equivalent representation in a variety of programming languages (including C++ and COBOL).

Although some level of competition was inevitable, both Sun and the OMG community (Sun being one of the founding and most active members of the OMG) understood implicitly that a three-way battle among DCOM, RMI, and CORBA would certainly lead to mutual failure (or at best, a Pyrrhic victory). The real question was how do these technologies coexist and cooperate, and what role should each have in a combined solution?

COEXISTENCE OR COOPERATION?

The simplistic answer was something along these lines: Use RMI when you're developing new Java-distributed applications; use CORBA when you need to access existing non-Java applications. It may be pointed out that the amount of IT budget allocated for maintaining and integrating non-Java production systems was, and remains for the foreseeable future, many times larger than that spent on new development in any language.

In any event, this answer (being little more than a statement of the superficially obvious) was not satisfactory to a large number of IT customers who had already made a significant investment in CORBA technology, but who also badly wanted to do new development in Java. At the time, RMI had its own completely separate infrastructure, sharing essentially nothing with CORBA infrastructure. It had its own messaging protocol (JRMP), its own registry mechanism, and was developing its own set of services that were similar to, but not compatible with, existing CORBA services. Corporate IT organizations aren't particularly enthusiastic about being forced to maintain and support two gratuitously different infrastructures. A clear (and harshly worded) message was delivered to both communities: We want to program in Java, using both CORBA and RMI programming models where appropriate, but we don't want two infrastructures. Make that happen!

The result became known as "RMI over IIOP." Understanding what this really means hinges on understanding the relationship between distributed programming models and their underlying protocols. More specifically, how programming models and protocols are simultaneously independent of, and interdependent upon, each other.

PROGRAMMING MODELS AND PROTOCOLS

RMI Programming Model

RMI is a programming model. When a Java programmer writes an application that uses RMI, s/he has a certain set of techniques available for use, design decisions to make, and constraints to observe. As mentioned earlier, a remotely accessible interface must be specifically designed and built as one, extending a particular base interface, and observing certain constraints on method signatures.

For example, all methods must throw certain exceptions, and all parameters must be serializable. Most of the mechanical work is done by the Java compiler and the RMI post-processor, producing proxies and skeletons that automate binding to servers, marshaling requests, and managing communication. Implementing and using a remote object takes slightly more work than simply constructing a local object and invoking its methods. A client must obtain a reference to the object from the RMI registry or JNDI directory. The implementation class must perform some bookkeeping rituals, including registering instance references or publishing them in the directory. Both client and server must also be designed to accommodate the basic issues of distributed computing:

  • Requests typically take milliseconds instead of microseconds.
  • There are a lot of news things that can go wrong over a wire.
  • There is a great deal of uncertainty about what may or may not have happened on the other end of the wire.

CORBA Programming Model

CORBA also presents users with a stylized programming model (or perhaps, models, given the variations that exist across different language mappings). The designer/programmer defines distributed interfaces in a separate IDL. An IDL compiler generates proxies and skeletons (much like those generated by the RMI post-processor) in a particular programming language, according to standardized rules called language mappings, defined by the OMG.

Until recently, the data types usable as operation parameters were limited to the usual primitive types, plus a small set of constructed types such as structs, unions, arrays, and sequences. The details of the CORBA programming model are largely determined by the programming language being used for the application and the IDL mapping defined for that language.

PROGRAMMING MODEL AND PROTOCOL SEMANTICS

In general, programmers using RMI or CORBA are not directly aware of the underlying protocol being used to make remote requests. The whole point of an abstract distributed object model is to make low-level issues, such as communications, transparent to the programmer. This is particularly true of the underlying transport protocol; it's pretty obvious that an application using a high-level abstraction such as an ORB doesn't know or care whether the messages are being exchanged over TCP/IP or SPX, because the transport protocol's job is simply to move bytes.

But RMI and CORBA both define messaging protocols, called (respectively) JRMP and IIOP. In general, such messaging protocols are not as independent of the programming model as the transport layer. A messaging protocol necessarily embodies the semantics of the programming model it implements. For example, messaging protocols for distributed object systems specify how object references are used to locate and identify specific instances, directly reflecting (or in some cases, defining) the concept of object identity for the object model. These protocols must also support the information model inherent in requests and replies, including what parameter data types may be exchanged and how they are encoded, what kinds of exceptions may be returned, whether any implicit context (such as a thread-associated transaction context or principal identity) is transmitted with the request and how, and so on.

JRMP was designed to support RMI's semantics. Likewise, IIOP was designed to support CORBA's semantics. It is a non-trivial problem to efficiently support the semantics of one programming model with a messaging protocol designed for a different programming model. Besides mismatches in data typing systems (which are the most obvious problems), there may be some basic differences in request semantics. For example, a particular protocol may (or may not) support certain capabilities that indirectly surface in the programming model as, for example, quality-of-service features or the ability to participate in distributed transactions.

RMI AND CORBA SEMANTIC DIFFERENCES

The biggest difference between RMI and CORBA, which manifests itself as differences between JRMP and IIOP, occurs in the types that can be used for remote operation parameters. CORBA has constrained itself to relatively simple types in order to remain consistent between languages and guarantee no loss of information when requests are made between different languages.

RMI, however, was under no such design constraint. It supports the ability to pass instances of arbitrary Java classes as parameters by value. This means that the remote request passes the complete state of the parameter object to the destination, where a new instance of the class is created with the same state in the local address space of the destination. The important difference is that the parameter embodies both state and behavior (in that the parameter object has methods that you can invoke).

At the time, CORBA operations could pass only pure state by value, in the form of structs, sequences, etc. CORBA and RMI operations can pass object parameters by reference, meaning that the object is not duplicated in the destination address space--the destination receives a handle for the object by which it can make remote invocations. This limitation in CORBA reflects its language-independent design center. It isn't particularly meaningful to try to pass a Java object to a C++ or COBOL application.

IDL VALUE TYPES

In order to use IIOP as the messaging protocol for RMI programs, IIOP needed to support the semantics of RMI that did not, at that time, exist in CORBA--primarily the ability to pass objects by value. The OMG did precisely this, not by extending IIOP directly but by extending the basic CORBA typing system to include the ability to define value types (that is, local programming objects) in IDL and pass them by value as parameters in requests. Value types were designed to express Java objects, but are not limited to that. Value types are language independent. At present, value type language mappings exist for Java and C++ and are being developed for other languages.

Using value types in non-Java languages poses some difficulties. Value types (such as class types in object-oriented programming languages) support inheritance and polymorphism, meaning that you can pass a parameter object whose actual type is more derived than the formal type declared in the operation signature. There is no guarantee that the destination of the request (or reply) knows what that type is or has the code that implements that type available locally. In Java programs, the destination can download the correct implementation on the fly. This is, for all practical purposes, impossible in programming languages that execute as native binary code. CORBA value types partially solve this problem by allowing derived value types to be truncated (that is, the information that constituted the more derived type is thrown away) to a base type, at the discretion of the programmer. In cases where no implementation is available and the type can't be truncated, the request throws an exception.

RMI OVER IIOP: RMI/CORBA UNIFICATION

In the process of defining a new IDL type, the rest of the CORBA specification was updated to accommodate value types, including the IIOP specification. Consequently, IIOP version 1.2 (the version of IIOP included as part of CORBA 2.3) supports the semantics required to be used as a messaging protocol for RMI.

In theory, it would have been possible to define a mapping (that is, a set of marshaling rules) from the RMI programming model to the new extended IIOP and stop there. It's a good thing that the OMG didn't do that, because the most valuable byproduct of this entire exercise would have been lost. Instead of mapping RMI to IIOP, the OMG defined a mapping from Java RMI to IDL. This means that an RMI interface description can be converted into an equivalent IDL interface.

This has profound implications for users of these two technologies. It is now possible to take an application written in Java, using RMI, and add new clients written in some other language without changing any RMI interfaces.

Conversely, it is possible to take the same application and replace object implementations in the server environment with implementations written in other languages. To do this, you need an ORB product that supports the Java-to-IDL mapping. The product (usually in the form of a byte code post-processor) reads the class files that include the RMI remote interfaces and generates equivalent IDL. You can then process this IDL with your normal IDL compiler (assuming it supports value types and other CORBA 2.3 extensions), producing stubs and skeletons for the language of your choice. At runtime, RMI stubs marshal requests into IIOP messages on one end, and the IDL-generated skeleton in, for example, C++, unmarshals the request, instantiating value types from the parameters that were marshaled as Java objects. The non-Java program must have been built to include implementations of value types equivalent to the corresponding Java classes used as parameters.

In essence, the OMG did not just define a means to use IIOP as the protocol for RMI requests. Rather, they defined an interoperability solution for RMI and CORBA, making it possible for programs built with both technologies to communicate directly, without any "impedance mismatch."

IIOP PUTS THE "E" IN EJB

While interoperability between RMI and CORBA is an interesting and useful goal, it is secondary to other possibilities that RMI/IIOP unification opens up. The most significant impact of RMI/IIOP integration is on Enterprise JavaBeans. EJB has adopted IIOP as the standard protocol for on-the-wire interoperability. Other protocols are permitted, but IIOP is required for conformant EJB implementations to interoperate with one another. Some of the reasons for this choice are:
  • EJB defines product interoperability based on an accepted industry standard that had proven itself as an effective means for product interoperability in the CORBA arena.
  • EJB can leverage the sizeable industrywide investment in IIOP, exploiting new advanced capabilities evolving in CORBA systems.
  • EJB can interoperate with deployed CORBA applications and use interoperability with CORBA for connectivity to non-Java production systems and data sources.
  • IIOP can scale to meet the demands of large enterprise systems, reducing the risks associated with developing a new protocol for distributed object systems.

Leveraging Industry Investment in CORBA

CORBA, including IIOP, has been in widespread development and use for considerably longer that any other distributed object technology. CORBA implementations are available from a large number of vendors. Competition among vendors has led to improvements in IIOP implementations, which in turn have led to new capabilities being added to the CORBA specification itself, including new extensions to IIOP, including:
  • The definition of standards for managing IIOP connections through firewalls, including standards for IIOP proxies, tunneling, and improved connections in firewall environments
  • A powerful, object-oriented distributed transaction model, including distributed two-phase commit, nested transactions, and integration with standard transactional resources through XA interfaces
  • Support for asynchronous, time-independent requests, with the ability to select various qualities of service, such as store-and-forward delivery and specified time-to-live for messages
  • Flexible, powerful security mechanisms for distributed authentication and encryption

Even more new capabilities are in progress, including:

  • Standards for using the same message formats as IIOP (called GIOP) with new high-speed transports such as ATM, RUDP, and FireWire
  • Standards for reliable, fault-tolerant systems using IIOP
  • Using multicast transports with IIOP

By choosing to specify IIOP as its standard protocol, EJB can exploit the investments made in IIOP by a variety of competing vendors and the emerging specifications in the OMG.

Integrating with Heterogeneous Systems

Enterprise systems are inherently heterogeneous. Even if IT organizations make concerted efforts to standardize on technologies, they can only do so for limited periods of time. Eventually, even the most disciplined IT organizations accumulate a variety of technologies (operating systems, programming languages, networking technologies, etc.) that must work together. Because of its cross-platform, cross-language nature, CORBA has become the mechanism of choice for integrating disparate technologies. By interoperating via IIOP, EJB can directly access existing production systems wrapped in CORBA interfaces.

Eliminating Risk

CORBA systems using IIOP have been deployed for some time in real enterprise systems. IIOP has undergone considerable revision and evolution since its invention, based on experience obtained in real system development and deployment. It has been, so to speak, battle hardened. By standardizing on IIOP, EJB eliminates the risks and costs of developing another new distributed object protocol. In fact, IIOP delivers the "E" in EJB.

IMPLEMENTING EJB CONTAINERS THAT SUPPORT IIOP

It is possible--but not particularly advisable--to build an EJB container from the ground up, including a custom implementation of RMI over IIOP. It may not be obvious to the casual observer, but the most effective way to build a serious EJB runtime system is to start with a high-quality, up-to-date (that is, version 2.3) Java ORB. The EJB container interfaces can be implemented as a very thin API layer on top of CORBA. The CORBA POA (Portable Object Adapter), for example, provides all the capability needed to implement the required Bean lifecycle and transactional policies. If the underlying ORB supports the CORBA Object Transaction Service, then the transactional requirements for EJB are already met. EJB specifies the use of JTS for distributed transaction support. Although not commonly understood, JTS is simply the Java mapping for the IDL interfaces of CORBA OTS.

WHAT SHOULD I LOOK FOR IN AN EJB CONTAINER?

There are a variety of first-generation EJB containers on the market, none of which support all the requirements for a conformant, robust EJB implementation. Implementations of RMI over IIOP are only now becoming available and simply implementing RMI over IIOP does not necessarily provide all the potential benefits. Here are some capabilities to look for in robust, conformant EJB containers:
  • A proven implementation of IIOP, including recent revisions for IIOP and the Java-to-IDL mapping
  • Integrated support for distributed two-phase commit in a robust implementation of JTS/OTS
  • Demonstrable interoperability with established ORB products
  • Demonstrable scalability and reliability of the supporting infrastructure
  • Support for the CORBA Firewall specification
  • Usable security mechanisms based on CORBA specifications

SUMMARY

The integration of Java and CORBA technologies is a response to a strong demand from the user community. The approach taken to integrate RMI and IIOP has benefits that extend far beyond the scope of just the programming model and the protocol. Ultimately, the broad acceptance of Java and EJB is made more promising by the fact that it can exploit years of experience and investment in CORBA technology.