Search
 
     
   
   
 
  Inside the IDL to Java Mapping
 
 


Though Java and CORBA are complementary technologies, Java has a private world of its own and so does CORBA. All CORBA objects were intended to live beyond a programming language world like that of Java or C++. In fact, all CORBA objects live in a virtual world with semantics of their own, and remember, they can only be accessed through the interfaces they expose. Another point to be noted is that CORBA does not associate remoteness into the objects, only location transparency is what is introduced at this point.

Blending Java and CORBA

As we all know that Java is a simple language to learn. I would say the same for CORBA. If both are simple, how could it be that the mapping is complex? CORBA has a well-defined set of basic and complex types that Java has in abundance as well. However, there were structural features of CORBA that Java lacked. The structs and unions were missing in Java. So were the typedefs and enumeration. Java's logic was simple, everything can be achieved as a class and the mapping is a simple testament to this principle. Let's take a closer look at the mapping specification.

From the beginning, it would have been possible for a very tightly integrated mapping to Java, with less semantics of CORBA made visible. Some of the goals of mapping are listed below:

  • Client side and server side source code portability
  • ORB replaceability
  • Binary compatibility between client stubs/sever skeletons and the ORBs.
  • Reverse mapping was also considered.
ORB Replaceability

Most of the mapping stops short of defining an interface for the stubs/skeletons and the ORB. This was usually left as an exercise for the ORB vendors. However, in the case of Java, an interface between the stub/skeleton and the ORB would be best suited.

Imagine the scenario of having a CORBA enabled Applet downloaded to a Netscape browser. However, the server side is written in OrbixWeb. Suppose you have different versions of the stub and skeleton code, then the application developer would have to recompile the IDL file each time an incompatible ORB was found on the client side. In the eventuality of having to cope with a non-compatible ORB, the ORB code is to be downloaded into the local machine along with the stub and skeleton code, which is not a good proposition for most of the clients.

So is the case for downloading of the skeleton code. An alternative to this is to use the dynamic invocation interface, which however is not efficient. Hence, it is required of a compliant ORB, be it at the client side or at the server side, they have to adhere to the interface specifications that exist between the stub/skeleton and ORB.
All the stubs inherit from the org.omg.CORBA.portable.ObjectImpl class.

Request Transfer Mechanism
  • Stream-based approach (stub and skeleton) Stream based skeletons directly extend from the org.omg.PortableServent.Servant.
  • DII based approach (stub)
  • DSI approach (skeleton) DSI based approach extends from the org.omg.PortableServer.DynamicImplementation class.
This is one way of achieving the binary compatibility. The main advantage of this approach will be the generation of applets that can work with any Java Mapping complaint ORB's stubs and skeletons.Mapping Types -Basic and Complex

Basic Types:
boolean boolean
char char - CORBA::DATA_CONVERSION
wchar char
octet byte
string java.lang.String - CORBA::DATA_CONVERSION, CORBA::MARSHAL
wstring java.lang.String - CORBA::MARSHAL
short short
unsigned short short
long int
unsigned long int
long long long
unsigned long long long
float float
double double
fixed java.lang.BigDecimal - CORBA::DATA_CONVERSION
any CORBA.Any class

Complex Types:
Mapping of struct:

A struct is mapped to a final class with public members, just as in the case of a struct that is seen in C/C++. It's definitely not familiar for Java programmers to use public members. You can use either the null constructor or a constructor, which takes arguments in the order of members declared in the IDL struct.

In a way, you can use this to pass objects by value; however, this is not the best of solutions. It would be better if you are able to send an object as a sequence of octets and have your own marshalling function defined.

Mapping of union:

This is another of those C/C++ features with little application in the current world. A union will be mapped to a final class with

  • Default constructor
  • Assessor methods for the discriminator, named discriminator
  • An assessor method for each branch · A modifier method for branch
  • A modifier method for each which has more than one case labels
  • A default constructor method of needed.
Mapping of array:

An array is mapped to a Java Array. It is simple and efficient. The bounds of the marshaled array is checked and this would result in a CORBA::MARSHAL exception if an incompatibility is detected.

Mapping of sequence:

A special array, which can vary in size. There are two types of sequences. Those that are bound to a maximum size and those that are not delimited by an upper limit.. The advantage that sequence has over an array is simple, you do not have to pass extra data if it is not necessary. As for an array, you have to initialize unwanted elements as well. Hence, a sequence is widely used.

A sequence is mapped to a Java array with the same name. In the mapping, everywhere the sequence type is needed, an array of the mapped type of the sequence element is used. Bounds checking shall be done on bounded sequences when they are marshaled as parameters to IDL operations and an IDL CORBA::MARSHAL exception is raised if needed.

Mapping of enum:

IDL enum is mapped to a Java final class with the same name as the enum type, which declares a value method, two static data members per label, an integer conversion method and a private constructor.

Mapping of exception:

IDL exceptions are mapped to Java exception classes. CORBA system exceptions are unchecked exceptions. They inherit from java.lang.RuntimeException.

User defined exceptions are checked exceptions. They inherit from java.lang.Exception.

Mapping of interfaces:

The most important of them all feature in CORBA. As we all know, an IDL is used primarily for specification, and to specify your system in object oriented terms, you do so with the help of interfaces.

An IDL interface is mapped to the Java equivalent - interfaces. But we need to put CORBA semantics into the interface and for this purpose, they inherit from another interface - org.omg.CORBA.Object interface.

The Java interface contains the mapped operation signatures. Methods can be invoked on an object reference to this interface. Attributes are mapped to get and set methods, with the exception of read-only attributes, which can have only get methods generated. out and inout parameters have their holders as generated argument signatures.

Mapping of modules:

Simple, they are mapped to packages.

Mapping of typedefs:

Recursively unwound to the original type.

Mapping of constants:

Depends upon the scope in which they are defined. If it's defined in an interface, the constant declarations - public static final type is added to the Java interface. However, if it is declared outside one interface, they are mapped to public interfaces with the same name as the constant and containing a public static final field, named value, that holds the constant's value. Note that the Java compiler will normally inline the value when the class is used in other Java code.

Helpers and Holders

The helper classes are classes that contain methods that are needed to access type information, Any insertion and extraction and portable methods to manipulate the input/output streams. What is special about all these methods, are that they are static .

Type Information Static Method
Static method Function
id() Get the Repository ID
type() Get the typecode
narrow() Downcast
insert()/extract() Manipulation
read()/write() Provide portable access to the input and output streams

Holders are containers that contain the respective type. Mainly used for the passing of a particular type by reference. This constrain is not visible in C++ as it has the pass by reference semantics to it. As in the case of Java, when you pass a reference, you pass it by value and not by reference. This is much visible when you attempt to swap two objects, say of type Person. You will be able to achieve this with the help of a container that contains the reference.

ORB interface

You still need APIs to connect to the CORBA world. This can be done using the init() method in the ORB abstract class that is provided by the ORB interface. Initializing an ORB in an applet is different from that of applications.

Java Portability Interfaces:

These are API's used to provide the minimal set of functionality to allow portable stubs and skeletons to be used with a Java ORB. Let's talk about the design goals (I quote from the mapping specification):

Size: Stubs and skeletons must have a small bytecode footprint in order to make downloading fast in a browser environment and to minimize memory requirements when bundled with a Java VM.

Performance: Care must be taken to minimize temporary Java object creation during invocations in order to avoid Java VM garbage collection.

Reverse Mapping: The design does not require adding methods to user defined types such as structures and exceptions. It need not ensure that stubs and skeletons generated by IDL to Java compilers and reverse Java to IDL mapping tools are interoperable and binary compatible.

For this purpose, the mapping has adopted a delegation-based approach to achieve the goals stated above. Also, the stubs and skeletons use the DII and DSI to achieve maximum portability.

The major components of the architecture are:

  • Portable Streamable - provides standard APIs to read and write IDL datatypes (discussed above in the Helper section).
  • Portable Streams - provide standard to the ORB marshalling engine (classes like the InputStream and the OutputStream).
  • Portable Stubs and Skeletons - discussed above.
  • Portable Delegate - provides vendor specific implementation of CORBA object.
  • Portable Servant Delegate - Provides vendor specific implementation of the PortableServer::Servant.
  • ORB initialization - discussed above.

I would like to talk more about the Portable Delegate. The Delegate abstract class specifies a portable API for ORB-vendor-specific implementation of the org.omg.CORBA.Object methods. When a proxy is instantiated a delegate object is passed to it. All calls to org.omg.CORBA.Object methods are forwarded to this class. This allows a stub generated by one vendor's ORB to work with the delegate from another vendor's ORB. Operations like create_request(), equals(), is_a(), is_equivalent(), is_local(), hash() are all delegated to the ORB through the delegate object. All this is applicable to the stubs. There are compatible operations for the skeleton as well. This is one of the best mappings that I have seen.

You will see more of valuetypes and components in the forthcoming discussions.


   - Mr. Jacob Jose Cherakal - Software Architect,

1. CORBA® is a trademark of a Object Management Group, Inc., registered in the United States of America
2. Java™ is a trademark of Sun Microsystems, Inc.
 
     
     
Copyright © 2006 iCMG. All rights reserved.
Site Index | Contact Us | Legal & Privacy Policy