CORBA-Java IDL-Java Meets CORBA - Part 1
03 Oct 1998Distributed-Computing
Distributed object computing extends an object-oriented programming system by allowing objects to be distributed across a heterogeneous network. Then each of these distributed object components interoperates as a unified whole. These objects may be distributed on different computers throughout a network and living within their own address space outside of an application, yet appear as though they were local to an application.
Three of the more popular distributed object paradigms are Microsoft’s Distributed Component Object Model (DCOM), OMG’s Common Object Request Broker Architecture (CORBA), and Sun’s Java/Remote Method Invocation (Java/RMI). In this article, you learn about the CORBA architecture and the mechanics of developing CORBA clients and servers.
The CORBA Distributed Computing Model
CORBA is a structural architecture designed to support heterogeneous object systems. CORBA achieves communication between different distributed objects while still allowing encapsulation and hiding of the internal object structure from external objects through Indirection. CORBA uses Indirection efficiently to achieve encapsulation preventing systematic recompilation.
CORBA defines a model that specifies interoperability between distributed objects on a network in a way that is transparent to the programmer. CORBA achieves this by defining ways for specifying the externally visible characteristics of a distributed object in a way that is implementation-independent.
This model is based on clients requesting the services from distributed objects or servers through a well-defined interface, by issuing requests to the objects in the form of events. An event carries information about an operation that needs to be performed, including the object name (called an object reference) of the service provider and the actual parameters, if any.
CORBA automatically handles a lot of network programming tasks, such as object registration, object location, object activation, request demultiplexing, frame and error-handling, marshaling, and operation dispatching.
CORBA objects are accessed through the use of an interface. OMG’s Interface Definition Language (IDL, for short) is used to define interfaces, their attributes, methods, and parameters to those methods within the interface.
CORBA relies on a protocol called the Internet Inter-ORB Protocol (IIOP) for remoting objects. Everything in the CORBA architecture depends on an Object Request Broker (ORB). The ORB acts as a central Object Bus over which each CORBA object interacts transparently with other CORBA objects located either locally or remotely. Each CORBA Server Object has an interface and exposes a set of methods. To request a service, a CORBA client acquires an object reference to a CORBA server object. The client can now make method calls on the object reference as if the CORBA server object resided in the client’s address space. The ORB is responsible for finding a CORBA object’s implementation, preparing it to receive requests, communicating requests to it, and carrying the reply back to the client. A CORBA Object interacts with the ORB, either through the ORB interface or through an Object Adapter, which comes in two flavors: Basic Object Adapter (BOA) or Portable Object Adapter (POA).
Some of the benefits of CORBA include, but are not limited to, the following:
- CORBA forces a separation of an object’s interface and its implementation.
- CORBA’s support for reuse is inherent to the technology.
- CORBA is scalable.
- CORBA enforces transparency of platforms and languages.
- CORBA provides interoperability.
- CORBA abstracts network communication from the developer.
Because CORBA is just a specification, it can be used on diverse platforms, including Mainframes, UNIX, Windows, AS/400, and so forth as long as an ORB implementation exists for that platform. Currently, major ORB vendors like Inprise and Iona offer CORBA ORB implementations for numerous platforms.
The Object Management Architecture
OMG, the industry consortium that created the CORBA standard, defines two basic models on which CORBA and all its standard interfaces are based. They are
- The Core Object Model and
- The Reference Model
The Core Object Model defines concepts that facilitate distributed application development using the Object Request Broker (ORB). It defines a framework for refining the CORBA model to a concrete form. The Core Object Model is an abstract specification that does not attempt to detail the syntax of object interfaces or any other part of the ORB This model provides the basis for CORBA, but is more relevant to ORB designers and implementers than it is to application developers.
The Figure 1 shows the OMA Reference Model.
Figure 1: The Object Management architecture
The Reference Model defines a development model for CORBA and its standard interfaces through which developers can create and use frameworks, components, and objects. This model places the ORB at the center of a grouping of objects with standardized interfaces that provide support for application developers. In addition to the ORB, the Reference model identifies four groupings:
- Object Services, which provide the infrastructure.
- Domain Interfaces, which provide support for applications from specific industry domains.
- Common Facilities, which provide application-level services across domains.
- Application Interfaces, which is the set of objects developed for a specific application.
The CORBA 2.0 architecture
Figure 2 shows the CORBA 2.0 architecture. In CORBA, the IDL compiler generates type information for each method in an interface and stores it in the Interface Repository (IR). A client can thus query the IR to get run-time information about a particular interface and then use that information to create and invoke a method on the remote CORBA Server Object dynamically through the Dynamic Invocation Interface (DII). Similarly, on the server side, the Dynamic Skeleton Interface (DSI) enables a client to invoke an operation of a remote CORBA Server Object that has no compile time knowledge of the type of object it is implementing.
Figure 2: CORBA 2.0 architecture
The Object Request Broker (ORB)
The central component of CORBA is the Object Request Broker (ORB). This component provides all the communication infrastructure needed to identify and locate objects, handle connection management, and deliver data and request communication.
One CORBA object never talks directly with another. Instead, the object requests for an interface to the ORB running on the local machine. The local ORB then passes the request to an ORB on the other machine. The remote ORB then locates the appropriate object and passes back an object reference to the requester.
The functions of the ORB are as follows:
- Lookup and instantiate objects on remote machines
- Marshal parameters from one application object to the other
- Handle security issues across machine boundaries
- Retrieve and publish data on objects on the local machine for another ORB to use
- Invoke methods on a remote object using static method invocation
- Invoke methods on a remote object using dynamic method invocation
- Automatically instantiate objects not currently running
- Route callback methods to the appropriate local object being managed
- Communicate with other ORBs using the Internet Inter-ORB Protocol (IIOP)
Object Adapters
An Object Adapter is a server-side facility that provides a mechanism for the CORBA object implementations to communicate with the ORB and vice versa. An Object Adapter also extends the functionality of the ORB. An Object Adapter is layered on top of the ORB Core to provide an interface between the ORB and the object implementation. Object Adapters can also be used to provide specialized services optimized for a particular environment, platform, or object implementation.
Some of the services provided by an Object Adapter are
- Registration of server object implementations with the Implementation Repository
- Activation and deactivation of object implementations
- Instantiation of objects at runtime
- Generation and management of object references
- Mapping of object references to their implementations
- Dispatching of client requests to server objects through a skeleton or the Dynamic Skeleton Interface (DSI)
While many object adapter implementations may exist for unique situations, the CORBA specification only * requires implementations to provide a Basic Object Adapter (BOA) or a Portable Object Adapter (POA) which is a portable version of the BOA.
Basic Object Adapter (BOA)
The BOA is a pseudo-object and is created by the ORB, but it is invoked like any other object. The BOA provides operations the CORBA Server Object implementations can access. It interfaces with the ORB Core and with the skeletons of your object server implementation classes.
A BOA may be required to perform two types of activations on behalf of a client’s request: implementation activation and object activation.
Implementation Activation: This occurs when the implementation for the target object is unavailable to handle the request. This requires the use of a daemon that can launch a Java VM with the server’s byte code. The information necessary to associate an object implementation with a Java class is stored in the Implementation Repository.
Object Activation: This occurs when the target object is unavailable to handle the request.
The BOA is mandated by CORBA 2.0, but was recently deprecated in favor of a Portable Object Adapter (POA). Even though vendors, to support existing implementations, may support the BOA, OMG will no longer update the BOA specifications.
Portable Object Adapter (POA)
The POA addresses many problems found in applying the BOA. It mandates additional functionality and is tightly specified to increase portability. With the POA API, the interfaces between the ORB and the object’s implementation have been standardized. Thus, CORBA services stand a fighting chance of being ORB-independent as well as interoperable.
The Implementation Repository
The Implementation Repository is an online database that contains information about the classes a server supports, the objects instantiated, and their IDs. Additional information about a specific ORB implementation may also sometimes be stored here.
The Dynamic Skeleton Interface (DSI)
For CORBA components that do not have an IDL-based compiled skeleton, the Dynamic Skeleton Interface (DSI) provides a runtime binding mechanism. The DSI determines the target object for which a message is meant by looking at the parameter values in an incoming message, so it can receive either static or dynamic client invocations. The DSI thus allows servers to dispatch client operation requests to objects that were not statically defined at compile time.
Interface Repository
The Interface Repository (IR) is an online database of metainformation about ORB object types. Metainformation stored for objects includes information about modules, interfaces, operations, attributes and exceptions.
The Dynamic Invocation Interface (DII)
During run time, the DII allows methods to be discovered dynamically so they can be invoked. Client programs can obtain information about an object’s interface from the Interface Repository and dynamically construct requests to act on the object.
The Interface Definition Language (IDL)
Whenever a client needs some service from a remote distributed object, it invokes a method implemented by the remote object. The service the remote distributed object (server) provides is encapsulated as an object and the remote object’s interface is described in an Interface Definition Language (IDL). The interfaces specified in the IDL file serve as a contract between a remote object server and its clients. Clients can thus interact with these remote object servers by invoking methods defined in the IDL. CORBA supports multiple inheritance at the IDL level and allows exceptions to be specified in the IDL definitions.
A typical CORBA IDL definition looks like Listing 1.
module SimpleStocks {
interface StockMarket {
float get_price( in string symbol );
};
};
Listing 1: A typical CORBA IDL
The CORBA IDL file shows a StockMarket
interface with a get_price()
method. When an IDL compiler compiles this IDL file it generates files for stubs and skeletons.
IDL to Java Mapping
The highlights of the IDL to Java mapping are as follows:
- An IDL module maps to a Java package of the same name.
- An IDL interface maps to a public Java interface with the same name.
- Inheritance of IDL interfaces is achieved through inheritance of Java interfaces.
- Nested IDL type definitions are mapped to Java classes using a scoped package name.
- IDL attributes are mapped to a pair of overloaded Java accessor and mutator methods.
- All IDL out and inout parameters require the use of a Holder class.
Identifiers, Naming, and Scope
Except where a conflict would result with a Java reserved word, IDL names and identifiers are mapped directly to Java with no modification. Where a name or identifier in IDL exactly matches a Java reserved word, the collision is resolved by prepending an underscore (_) in the mapped name. For example:
// in IDL
interface synchronized {};
maps to
// generated Java
public class _synchronized {}
Depending upon the IDL construct, the mapping may require more than one uniquely named Java construct. When such a situation occurs, additional constructs are tagged on to the Java names like Helper, Holder or Package. In case any of these still conflicts with standard Java constructs, the collision resolution rule (_) applies.
Generated classes
In addition to the Java class that maps directly from an IDL construct, helper and holder classes may be generated to aid the developer in the use of the class.
Holder classes
Because all parameters are passed by value in Java, a method may change only the state of an object passed to it, not the reference to the object itself. To allow IDL types to be used with out and inout parameter passing modes, additional holder classes are required. The holder classes provide a level of indirection and are passed instead of the actual type. The client instantiates a holder object and passes it in the operation invocation. The server may then set or modify the value member of the holder object. Because the encapsulated actual object is modified without affecting the holder object reference itself, the semantics of out and inout parameters are supported. Holder classes are available for all the basic IDL datatypes in the org.omg.CORBA package and are generated for all named user-defined types, except those defined by nonconstructed type typedefs.
Helper classes
All user-defined IDL types have an additional helper Java class with the suffix Helper appended to the mapped type name. A helper class contains convenience and utility methods for operating on the associated object. The purpose of the helper class is to prevent bloating of the mapped classes with methods that may not be needed. The class provides methods for reading and writing the object to a stream, obtaining the object’s repopsitory identifier, and casting the object to/from a CORBA Any. The helper classes for mapped IDL interfaces also have the narrow() method defined, which is used to cast the object reference of org.omg.CORBA.Object to the base type of the helper.
Mapping for basic types
Table 1 shows the mapping of the CORBA basic types to the corresponding Java class or type.
Table 1: The Mapping for Basic Types
IDL Type | Java Type | Exceptions |
boolean | boolean | CORBA::DATA_CONVERSION |
char | char | |
wchar | char | |
octet | byte | |
string | java.lang.String | CORBA::MARSHAL, CORBA::DATA_CONVERSION |
wstring | java.lang.String | CORBA::MARSHAL |
short | short | |
unsigned short | short | |
long | int | |
unsigned long | int | |
long long | long | |
float | float | |
double | double |
Mapping for enum
An IDL enumeration (enum) is mapped to a public Java final class. Each enumeration has two corresponding static class constants: one is a Java int named with a prepended underscore to the element identifier and the other is an instance of the mapped final class with the same name as the element that represents the element’s value.
// in IDL
enum TrafficLight {red, yellow, green};
maps to
// generated Java
final public class TrafficLight {
final public static int _red = 0;
final public static int _yellow= 1;
final public static int _green = 2;
final public static TrafficLight red = new TrafficLight(_red);
final public static TrafficLight yellow= new TrafficLight(_yellow);
final public static TrafficLight green= new TrafficLight(_green);
public int value() {....}
....
}
Mapping for struct
An IDL struct maps to a final Java class containing one instance variable for each structure field. The class name is the same as the IDL structure name. Two constructors are provided: one takes the fields of the structure as arguments to initialize the instance variables and the other is a null constructor that initializes the instance variables to null or zero.
Mapping for union
An IDL union is mapped to a final Java class that has the following characteristics:
- Same name as the IDL identifier
- A default constructor
- An accessor method for the union’s discriminant named discriminator()
- An accessor method for each variant
- A mutator method for each variant
- A mutator method for each variant that has more than one case label
- A default mutator method if needed
Mapping for ordered collections
CORBA provides two types of ordered collections: sequences and array. A sequence maps to a single dimensional Java array, which may be either bounded or unbounded. An IDL array is a multidimensional array whose size, in each dimension, must be fixed at compile time.
Mapping for attributes and operations
Attributes are mapped to a pair of overloaded Java accessors and mutator methods. These methods have the same name as the IDL attribute and differ only in their signature. No mutator method exists for IDL read-only attributes.
Parameter-passing modes
IDL in parameters, which implement call-by-value semantics, are mapped to normal Java actual parameters. The results of IDL operations are returned as the result of the corresponding Java method.
IDL out and inout parameters, which implement call-by-result and call-by-value/result semantics, cannot be mapped directly into the Java parameter-passing mechanism. This mapping defines additional holder classes for all the IDL basic and user-defined types used to implement these parameter modes in Java.
Table 2 shows the mapping of IDL type to Java for the different parameter modes.
Table 2: Mapping of CORBA IDL to Java for different parameter modes
IDL Type | In Mapping | In/out Mapping | Return Mapping |
boolean | boolean | BooleanHolder | Boolean |
char | char | CharHolder | Char |
wchar | char | CharHolder | Char |
octet | byte | ByteHolder | Byte |
string | Java.lang.String | StringHolder | java.lang.String |
Wstring | Java.lang.String | StringHolder | java.lang.String |
short | short | ShortHolder | Short |
Unsigned short | short | ShortHolder | short |
long | int | IntHolder | Int |
Unsigned long | int | IntHolder | int |
Long long | long | LongHolder | Long |
Unsigned long long | long | LongHolder | long |
float | float | FloatHolder | Float |
Double | double | DoubleHolder | double |
Enum | < enum >Holder | < enum >object | |
Struct | < struct >Holder | < struct >object | |
Union | |||
Sequence | |||
Array | |||
Any | Any | AnyHolder | Any |
interface |
Mapping for user-defined exceptions
A user-defined exception is mapped to a final Java class that extends org.omg.CORBA.UserException. The UserException class extends the standard org.omg.CORBAexception class. The mapping is identical to the IDL struct type, including generated Holder and Helper classes.
Mapping for system exceptions
The standard IDL system exceptions are mapped to final Java classes that extend org.omg.CORBA.SystemException and provide access to the IDL major and minor exception code, as well as a string describing the reason for the exception. Instantiating org.omg.CORBA.SystemException is impossible. Only classes that extend it can be instantiated.
Developing CORBA Servers and Clients
When developing distributed applications for CORBA using the Java IDL, you first identify the objects required by the application. Figure 4 denotes the Java IDL development lifecycle.
Figure 4: Java IDL Development Lifecycle
You are usually required to follow these steps:
- Write a specification for each object using the IDL.
- Use the IDL compiler to generate the client stub code and server skeleton code.
- Write the client application code.
- Write the server object code.
- Compile the client and server code.
- Start the server.
- Run the client application.
Before developing CORBA servers and clients, make sure you have Java 1.2 and the idltojava compiler installed on your machine. The JDK provides the API and ORB needed to enable CORBA-based distributed object interaction. The idltojava compiler uses the IDL-to-Java mapping to convert IDL interface definitions to corresponding Java interfaces, classes, and methods, which you can then use to implement your client and server code.
Also ensure your Path and Environment variables conform to what is specified in the JDK installation docs. For more information about setting up these environment variables, see the Java JDK 1.2 Installation Guide.
You can always refer to my Homepage at webcornucopia.com for more CORBA source code. Another good resource is the comp-object-corba@omg.org mailing list from OMG. You can get the CORBA specs from omg.org.