|By Jeff Nelson||
|July 1, 1997 12:00 AM EDT||
RMI and CORBA are two different approaches for distributed object computing with Java. Industry experts have suggested that the two technologies are inherently incompatible with each other. In this series of columns I demonstrate how RMI could be immplemented on top of CORBA, resulting in the two technologies interoperating, and present some example applications of RMI working with CORBA. In this issue, we'll look at the differences and similarities between the two approaches.
In the last issue of Java Developer's Journal (Vol.2, Iss. 6), David Curtis described RMI and CORBA and their different design centers for distributed computing with Java. JavaSoft has sent mixed signals regarding their support for one or both of these technologies in different parts of Java. RMI and CORBA are very different technologies in their approach to distributed computing.
However, RMI and CORBA are both object request broker (ORB) technologies. While RMI and CORBA are not identical, they do address the same problem, that of permitting an object in one program to invoke a method on an object in another program. This similarity makes the existing implementations of RMI and CORBA remarkably similar. In fact, some parts of their implementations are indistinguishable.
In this series of articles, I present a solution for implementing all of RMI completely on top of CORBA, resulting in the two technologies interoperating, and present some example applications of RMI working with CORBA. In this first article, I show how RMI's use of Remote objects can be implemented on CORBA, how RMI's exception handling conventions can be replaced by CORBA exception handling and how the RMI naming service can be implemented on top of the CORBA naming service. In the articles to follow, I will discuss pass-by-value, behavior passing and distributed garbage collection as they are presented in both RMI and CORBA, demonstrating how the RMI implementation of these can be replaced by a CORBA implementation, resulting in the seamless interoperability of the two technologies.
RMI and CORBA both allow developers to manipulate distributed objects, which are objects located in a different application or machine. Distributed objects give your application the ability to easily interact with other applications without writing a bunch of socket code. Distributed objects are represented by an object called a stub, which is a placeholder for an instance of the object in other programs. When the program invokes an operation on the stub, the stub writes the invocation onto a TCP/IP socket which is communicating with the instance of the distributed object running in another program.
In RMI, all distributed objects implement a common interface called java.rmi.Remote. When RMI detects that an object implements this interface, it treats the object as a distributed object. The main difference from the point of view of the ORB is that distributed objects are not sent across the network as a stream of bytes, as would normally be the case for communicating the arguments of a distributed method invocation. Instead, a stub is used to accept method invocations and forward them to an instance of the object running somewhere else, perhaps in another process or on another computer.
In CORBA, several ways are available to associate an object with a stub, including interface inheritance, delegation and a dynamic skeleton interface. For the purposes of implementing RMI, I chose to use the one method which corresponds most closely with the mechanism provided by RMI, interface inheritance. In the case of JacORB, one of many CORBA products available for Java, the base interface is called CORBject. The following is an implementation of RMI's Remote interface in terms of CORBject.
public interface Remote
} Since RMI requires that every distributed object inherit from the Remote interface, while CORBA requires that each distributed object inherit from the CORBject interface, this implementation lets every RMI distributed object automatically be treated as a CORBA distributed object!
RMI requires that every remote object throw an exception called java.rmi.RemoteException. This exception is used to indicate general system problems such as network failures, remote classes not found, etc. Every remote method on every remote object must throw this exception. For example, a typical method on an RMI remote object looks something like this:
void myFunction() throws RemoteException; CORBA has no such requirement. Instead, by convention, CORBA exceptions are all mapped to RuntimeException in Java, allowing the software developer to either handle them or ignore them at his discretion. All CORBA exceptions inherit from a common base class called System- Exception.
Merging the two different approaches to exception handling is quite easy. When the RMI interface is compiled into a CORBA interface, the extra RemoteException is simply added on to the end of the exception list. The above method would be compiled into the following IDL:
void myFunction() raises (RemoteException); The implementation of RemoteException, as with most Java exceptions, is simple, since the exception doesn't have to do anything itself.
public class RemoteException
Robust distributed systems usually depend on some sort of naming service as a directory to be used to store the location where objects can be contacted on the network. The naming service acts as a central repository for the location of these objects and is an important part of writing scalable software. Without this service, user code would contain the machine names used to host particular objects. If the user code did contain these machine names, then whenever the objects were moved from one computer to another, all the clients would have to be recompiled.
A naming service primarily has two main operations. First, a registration operation which is used to add a new listing for an object to the naming service. Second, a lookup operation which is used to find an object given a particular name.
RMI currently has early support for a naming service which is roughly called the RMIRegistry, although the class used to access this naming service within user code is called simply Naming. RMI Naming's registration and lookup operations are called respectively rebind and lookup.
CORBA supports two major types of naming services, called CosNaming and Trading. CosNaming is a simple list of names and objects. Trading is a more robust means of finding objects based on a SQL-like set of queries. However, for the purposes of implementing RMI's Naming on top of CORBA, I would like to use a proprietary feature of JacORB called NameServer, which provides a useful layer of abstraction above CosNaming. The registration and lookup methods of JacORB's NameServer are registerService and locate.
The implementation of RMI's lookup method is simply passed through directly to JacORB's NameServer. In practice, we actually parse and re-arrange the name argument just a little, but the code is essentially as simple as the following.
public static Remote lookup(String name)
return (Remote)NameServer.locate( name );
} The implementation of RMI's rebind is slightly more involved due to the details of how ORBs typically connect a running object to the network. An object called a "skeleton" is used which contains a reference to the running object, which knows how to read a byte stream representing a method invocation and dispatch the invocation to the object. So, in the implementation of RMI's rebind, a skeleton must be instantiated and registered with the NameServer. The implementation of rebind is shown in Listing 1.
Running the Demo
Although all of the features of RMI have not been discussed here, the RMI implementation presented so far is complete enough to run one of the standard RMI demos right on top of JacORB. This demo represents the traditional "Hello, World!" demo that every software developer writes when first trying out a new programming language. The server will pass the string "Hello, World!" to the client in a method invocation and the client simply prints this string out. That's all there is to it.
The first step is to start the RMI naming service. This is just a batch file which runs JacORB's naming service.
c:\> rmiregistry & Second, start the object server. This will instantiate a copy of the Hello object.
c:\> java examples.hello.HelloImpl & Finally, run the HelloApp on this server.
c:\> java examples.hello.HelloApp
Hello, World! That's it! The RMI demo successfully ran directly on top of CORBA.
The next natural question to ask is what benefits would be realized if RMI and CORBA interoperated with each other. To answer this question, consider that when information system managers at most companies talk about distributed processing, they mean multitier architectures where the backend is a mainframe, the middle tier is typically C++ on Unix or NT and the front end is a combination of C++, Java and Visual Basic. I have heard this design over and over again from Fortune 500 project managers. They generally also say something about wanting to move toward implementing all of their software in Java, but not being ready to throw out the mainframe or their 5 million lines of C++ code and 15 million lines of COBOL code, instead wanting to approach the transition incrementally. This task is impossible to complete with RMI because it is a Java-only tool and provides no way to access COBOL or C++. However, CORBA has robust support for virtually every language, including Java, C, C++, Ada, Visual Basic, Delphi, PowerBuilder, Smalltalk, Lisp, Python and Perl.
An RMI server written in Java would talk to a CORBA clientwritten in Visual Basic. Figure 1 shows an example of a Visual Basic front end that I used for a calculator object written for RMI. I must inform you that I did not write this Visual Basic front end myself though. I already had this Visual Basic CORBA client and could simply re-use it for this demo, even though it was talking to an RMI program on the other end.
RMI and CORBA are not such different beasts that they cannot be made to work together. In fact, I have demonstrated how RMI's Remote objects, RemoteExceptions, and Naming could be implemented on top of the corresponding features of CORBA. The benefits of living in an interoperable world are very great. I hope someday we all have a chance to enjoy this interoperability.