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-eVective way to build many more CORBA applications than C++; it oVered 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 diVerent: it uses Java's native type system to describe remote interfaces and their parameters, whereas CORBA uses a programminglanguage-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 diVerent 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, 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: 1) requests typically take milliseconds instead of microseconds; 2) there are a lot of news things that can go wrong over a wire, and 3) 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 diVerent 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 eYciently support the semantics of one programming model with a messaging protocol designed for a diVerent programming model. Besides mismatches in data typing systems (which are the most obvious problems), there may be some basic diVerences 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 diVerence between RMI and CORBA, which manifests itself as diVerences 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 diVerent 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 diVerence 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 (i.e., 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 diYculties. Value types (such as class types in object-oriented programming languages) support inheritance and polymorphism, meaning that I 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 (i.e., 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 (i.e, 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:
*Leveraging Industry Investment 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:
Even more new capabilities are in progress, including:
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 eVorts 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 eVective way to build a serious EJB runtime system is to start with a high-quality, up-to-date (i.e., 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:
*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.