Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

The MICO CORBA Compliant System


Nov98: The MICO CORBA Compliant System

Arno is working for the Deutsche Telekom AG and is currently on sabbatical at the International Computer Science Institute in Berkeley, California. He can be contacted at [email protected].


The Common Object Request Broker Architecture (CORBA) describes the architecture of a middleware platform that supports the implementation of applications in distributed and heterogeneous environments. The CORBA standard is issued by the Object Management Group (OMG), an international organization with over 750 information software vendors, developers, and users. In contrast to other middleware platforms (like Microsoft's DCOM), CORBA is a specification that does not prescribe any specific technology. In fact, the specification is freely available from the OMG (http:// www.omg.org/) and anyone can implement a CORBA-compliant system. In this article, I'll present one such system -- MICO (short for "Mico Is COrba"), a freely available CORBA implementation.

The MICO sources are available at http://www.icsi.berkeley.edu/~mico/. The compilation and installation of MICO requires the usual GNU tools. Precompiled binaries as well as a more detailed manual are available from Morgan Kaufmann Publishers (http://www.mkp.com/). The distribution currently contains binaries for IBM-AIX, Linux, DEC Alpha, and HP-UX. It should not be difficult to port MICO to any platform where GNU tools are available (for instance, we were able to compile MICO under Windows NT).

The current version of MICO supports:

  • IDL to C++ mapping.
  • Dynamic Invocation Interface (DII).
  • Dynamic Skeleton Interface (DSI).
  • Graphical Interface Repository browser that lets you invoke arbitrary methods on arbitrary interfaces.
  • Interface Repository (IR).
  • IIOP as native protocol (ORB prepared for multiprotocol support).
  • Support for nested method invocations.
  • An interface for inserting and extracting constructed types that were not known at compile time.
  • Full Basic Object Adapter (BOA) implementation, including all activation modes, support for object migration and the implementation repository.
  • BOA can load object implementations into clients at run time using loadable modules.
  • Portable Object Adapter (POA).
  • Support for using MICO from within X11 applications (Xt, Qt, and Gtk) and Tcl/Tk.
  • Naming service.
  • Event service.
  • Trading service.
  • Dynamic Any.
  • Interceptors.
  • Support for secure communication and authentication using SSL.

Overview of CORBA

Figure 1 presents an overview of the components required for a CORBA 2.0-compliant implementation (depicted in gray), as well as the embedding of an application in such a platform (white components). The Object Request Broker (ORB) is responsible for transferring operations from clients to servers. This requires the ORB to locate a server implementation (and possibly activate it), transmit the operation and its parameters, and finally return the results back to the client.

An Object Adapter (OA) offers various services to a server such as the management of object references, the activation of server implementations, and the instantiation of new server objects. Different OAs may be tailored for specific application domains and may offer different services to a server. The ORB is responsible for dispatching between different OAs. There is only one OA required for a CORBA 2.0-compliant implementation -- the BOA. As its name implies, it offers only basic services to a server.

The BOA has access to the Implementation Repository (IMR), which contains information concerning the activation of servers; for example, the location of the executable to handle particular incoming operations. The ORB, on the other hand, has access to an Interface Repository (IR) at run time. The IR holds information about the interfaces (IDL specifications, for instance) used within the domain of the ORB.

The interface between a client and server is specified by an Interface Definition Language (IDL). According to the object paradigm, an IDL specification separates the interface of a server from its implementation. This way a client has access to a server without being aware of the server's implementation details. An IDL compiler generates a stub for the client and a skeleton for the server, which are responsible for marshalling the parameters of an operation.

The Dynamic Invocation Interface (DII) allows a client to invoke a remote operation without requiring a stub, and likewise, the Dynamic Skeleton Interface (DSI) enables a server to receive an operation invocation without requiring a skeleton. Thus the DII and DSI represent generic methods for sending and receiving operations. A possible application for the DII and DSI is a gateway, which provides bridges between CORBA and other middleware platforms. Without the DII and the DSI, the gateway would have to be recompiled with the appropriate stubs and skeletons and restarted every time a new IDL specification is introduced to the system.

Design Criteria for an ORB

If someone sets out to implement the CORBA standard, it is necessary to decide on the design criteria according to which the implementation should be structured. The design principles which guided the implementation of MICO include:

  • Start from scratch. Use only what standard UNIX API has to offer. Don't rely on proprietary or specialized libraries.
  • Use C++ for the implementation.
  • Make use of widely available, nonproprietary tools.
  • Omit bells and whistles. Only implement what is required for a CORBA-compliant implementation. Run-time efficiency is not an issue.
  • A clear design, even for implementation internals, ensures extensibility.

The result of 10 months work and 90,000 lines of code, MICO is a fully CORBA 2.0-compliant implementation. Since MICO implements the Internet Inter-ORB Protocol (IIOP), it is fully interoperable with other CORBA implementations. Interoperability was successfully tested with Orbix from Iona, VisiBroker from Inprise, and Sun's JDK 1.2 beta 2 (which now includes a "little ORB").

MICO's Modular Architecture

The design of our ORB as the central component of a CORBA implementation follows a microkernel approach. This means that as much functionality as possible is moved outside the ORB in order to keep it small and efficient. Our implementation of IIOP demonstrates this principle.

The way parameters and operations are coded and transferred via TCP/IP between two ORBs is defined by the CORBA standard through IIOP; thus, it should be possible to run one application across ORBs from different vendors if they correctly implement IIOP. The CORBA standard purposely does not prescribe any specific technology for the implementation of IIOP. To facilitate the integration of future transport mechanisms between ORBs, we located the implementation of IIOP in MICO outside of the ORB.

In Figure 2, the implementation of the IIOP protocol is located in a special-purpose OA (IIOP client) and an object (IIOP server). When a client sends an operation, this operation first enters the ORB. The ORB then dispatches the operation to one of the OAs that have previously registered with the ORB. The decision of where to send the operation is solely decided on the basis of the object reference; the ORB itself has no knowledge of remote or local objects. If the server object resides in a different address space, the operation is dispatched to the IIOP client. This special-purpose OA opens a TCP/IP connection to a remote IIOP server. The IIOP server behaves like an ordinary CORBA object and forwards the operation to its local ORB. Here, the operation is dispatched by the ORB via the BOA to the server object.

Once an OA has taken over the responsibility of an operation invocation, the ORB does not need to know what the OA is doing with it. Whether the OA opens a TCP/IP connection or does something else is out of the jurisdiction of the ORB. Using this microkernel architecture we have also implemented the various activation modes CORBA prescribes for a compliant implementation by means of a special-purpose OA. This guarantees a modular and easily extensible architecture.

Which Came First?

An IDL compiler translates an IDL specification into the stubs and skeletons. The code that the IDL compiler generates for stubs and skeletons must be in the same programming language used in the implementation for the client and the server (client and server need not be written in the same programming language). The CORBA standard defines mappings from IDL to several high-level programming languages. According to the rules for CORBA compliance, an implementation has to offer at least one IDL language mapping to one high-level programming language: MICO implements the IDL-to-C++ mapping.

An IDL compiler works in two steps: The IDL specification to be translated is checked for correct syntax and semantics, and then code is generated for the target language according to the language mapping. These two steps are called the "front-end" and "back-end" processing in compiler construction terminology.

The front end of the IDL compiler must somehow pass on information to the back end. This data structure is commonly known as a "syntax tree." In this case, a careful analysis shows that the logical structure of the syntax tree is equivalent to the logical structure of the Interface Repository (IR). As previously noted, the IR is responsible for storing and retrieving IDL specifications.

Since the IR is mandatory for a CORBA-compliant implementation, MICO's IDL compiler makes use of the IR to pass information from front-end to back-end. Here, however, lies an interesting problem: Because the IR itself is a proper CORBA object, its interface is defined in terms of an IDL specification; this leads to a chicken versus egg problem, since implementing an IDL compiler requires an IR, and, since a stub and skeleton are necessary for the implementation of the IR, the converse is true as well. However, this issue is easily resolved via a bootstrap process: The stub and skeleton for the IR are first generated manually by the developer, and then later replaced by the ones automatically generated by the IDL compiler. If you download the sources for MICO, you will find code generated by the IDL compiler during this bootstrap process.

Another specialty of MICO is related to the code generated by the IDL compiler. The stubs and skeletons generated by the IDL compiler are responsible for marshaling the parameters associated with an operation. MICO's marshaling is done via a standard interface offered by the ORB, while other CORBA implementations came up with their own (and proprietary) interface. The stubs and skeletons in MICO use the DII and DSI that are mandatory for a compliant implementation; therefore, the code generated by the IDL compiler also demonstrates the uses of the DII and DSI interfaces of a CORBA platform.

Sample Application

The first step toward creating a distributed application with CORBA technology such as MICO is to define the interfaces between the objects of the application using IDL. As an example, I'll use a banking scenario: The server models a bank account where a client can deposit and withdraw money. Listing One (at the end of this article) shows one possible IDL specification for this.

The server implements three operations: deposit, withdraw, and balance. The keyword in denotes an input parameter, and similarly, the keywords out and inout denote output and combined input/output parameters. The IDL specification in Listing One is fed into the IDL compiler to generate a stub and a skeleton for this interface. Next, the server must be implemented as in Listing Two. The server provides an implementation for all the operations listed in the IDL specification. This implementation is represented by the C++ class Account_impl, and is derived from class Account_skel: a class part of the skeleton. The class Account_skel receives an operation invocation and dispatches it to the proper C++ method. The three methods of class Account_impl are declared as pure virtual methods in class Account_skel.

The first step of every CORBA application is the initialization of the ORB and the BOA. Following this, a new account object can be instantiated. The function object_to_string converts the object reference of the newly created object from an internal binary representation to an ASCII string. This string is called an Interoperable Object Reference (IOR) by the CORBA standard and allows clients to locate the account object. Clearly, the IOR must encode a hostname and port number for this to work. The question is how to transfer the IOR to the client. For the scope of our little example, we simply use a UNIX file to store the IOR. A better (but more complex) way would be to use CORBA's naming service.

Listing Three presents the implementation of the client which uses the account object. Like the server, it first initializes the ORB, and then the client reads the IOR from the previously created UNIX file. The client does not need to initialize the BOA, because the BOA is only required for server functionality. Subsequently, the function string_to_object is used to convert the ASCII representation of the IOR back to a binary representation. This leaves you with an object reference to an interface Object -- the base interface of all CORBA interfaces. The interface must now be downcasted to the proper type. This is accomplished by the function _narrow, which is also generated for every stub.

Once the object reference is downcasted to match the interface type "Account," the client can invoke any of the operations belonging to the interface. The operation invocation is indistinguishable from a normal C++ method call and it is transparent to the client whether the server resides in the same address space or on a remote host. In fact, if the server happens to reside in the same address space, then the operation invocation is mapped to an ordinary C++ method call with no extra overhead. Just as the server's location is transparent to the client, so is the programming language with which the server is implemented.

If you have installed MICO on your system, compiling the example is easy. MICO provides you with some wrapper scripts, which add proper command-line arguments to the compiler and linker (such as include directories). From a UNIX shell, use Example 1 to generate the executables of the bank demo. This example is part of a tutorial from the MICO documentation that comes with the sources. The tutorial enhances the example by showing how to use the CORBA activation modes or the persistency mechanism. Another component of MICO is a graphical browser for the IR.

IR Browser

A CORBA-compliant implementation must provide an Interface Repository (IR) which can be seen as a database for IDL specifications accessible at run time. The information managed by the IR is organized hierarchically. Two different types of objects are managed by the IR: those objects which can contain other objects (called "Container") and those which are contained in other objects (called "Contained"). The IDL-type const is an example of a Contained, whereas the IDL-type "interface" is a Container as well as a Contained (for example, it contains other objects like const declarations and can itself be contained in a module).

Upon starting the graphical IR-browser, top-level objects are represented by icons. Moreover, the IDL source code can be shown for each object. The contents of the objects representing containers may be viewed as if the user had descended one level along a branch of the hierarchy.

Figure 3 is the IR browser in action. Prior to starting the IR browser, the IR was fed the IDL specification from Listing One. The interface Account is a Container containing three Contained objects. Each of these Contained objects represents one of the operations belonging to the interface Account. The upper window shows the content of the interface Account, and the three icons on the right side denote the operations deposit, withdraw, and balance. The left side of this window shows the IDL source code of the currently selected operation, deposit.

The IR browser also permits calling arbitrary operations at run time using the DII. Using the information from the IR, the tool constructs a graph representing the signature of an operation. This graphical notation is derived from a knowledge representation technique called "conceptual graphs" (CG). The lower-right window from Figure 3 displays the signature of the operation deposit as a conceptual graph. The lower-left window shows the same conceptual graph; this time in its textual notation (white nodes are surrounded by square brackets and black nodes by round brackets).

Some of the white nodes represent actual parameters which can be edited using the tool. In Figure 3, the value of the node ULONG is changed from 0 to 100. The resulting conceptual graph represents the operation invocation deposit(100). The tool can also be used to construct arbitrary IDL types like struct or sequence on-the-fly via conceptual graphs. The MICO homepage contains an online demonstration in the form of a Java applet that connects you to an Account object running on one of our machines.

Lessons Learned

The CORBA standard represents a specification of a middleware platform. It leaves room for design and implementation decisions which must be carefully considered. Some parts of the CORBA Standard, such as the BOA, are underspecified. This led to different implementations of the BOA for different ORB vendors, making it impossible to just exchange the underlying ORB and recompile the application. The OMG has recognized this problem and has released the specification of a Portable Object Adapter (POA).

Although MICO is not a commercial product, it is used by many research institutes and companies. Universities find it useful for term projects, while other groups find the availability of the source code advantageous for their own research. Gnome (http://www.gnome.org/), a set of applications and desktop tools similar to CDE but based entirely on free software, uses MICO for the internal communication and activation of its components.

The CORBA standard is far from complete. Version 2.2 of the specification was released by the OMG early in 1998. Our goal is to keep MICO compliant to the most recent version of the standard. We hope that placing the sources under the GNU General Public License will encourage other programmers to contribute to MICO's development.

DDJ

Listing One

// File: account.idlinterface Account {
    void deposit( in unsigned long amount );
    void withdraw( in unsigned long amount );
    long balance();
};

Back to Article

Listing Two

// File: server.cc

</p>
#include <fstream.h>
#include "account.h"


</p>
// Implementation of interface Account
class Account_impl : virtual public Account_skel
{
private:
  CORBA::Long _current_balance;
public:
  Account_impl()
  {
    _current_balance = 0;
  };
  void deposit( CORBA::ULong amount )
  {
    cout << "Operation deposit( " << amount << " )" << endl;
    _current_balance += amount;
  };
  void withdraw( CORBA::ULong amount )
  {
    cout << "Operation withdraw( " << amount << " )" << endl;
    _current_balance -= amount;
  };
  CORBA::Long balance()
  {
    cout << "Operation balance() => " << _current_balance << endl;
    return _current_balance;
  };
};
int main( int argc, char *argv[] )
{
  // ORB and BOA initialization
  CORBA::ORB_var orb = CORBA::ORB_init( argc, argv, "mico-local-orb" );
  CORBA::BOA_var boa = orb->BOA_init( argc, argv, "mico-local-boa" );


</p>
  // Create new Account object
  Account_impl* server = new Account_impl;
  // Write IOR to file
  ofstream out( "account.ior" );
  CORBA::String_var ref = orb->object_to_string( server );
  out << ref << endl;
  out.close();


</p>
  // Start processing incoming operations
  boa->impl_is_ready( CORBA::ImplementationDef::_nil() );
  orb->run();


</p>
  CORBA::release( server );
  return 0;
}

Back to Article

Listing Three

// File: client.cc

</p>
#include <iostream.h>
#include <fstream.h>
#include "account.h"


</p>
int main( int argc, char *argv[] )
{
  // ORB initialization
  CORBA::ORB_var orb = CORBA::ORB_init( argc, argv, "mico-local-orb" );


</p>
  // Read IOR from file
  ifstream in( "account.ior" );
  if( !in ) {
    cerr << "Can not open file 'account.ior'" << endl;
    return -1;
  }
  char ref[1000];
  in >> ref;
  in.close();


</p>
  // Generate object reference from stringified IOR
  CORBA::Object_var obj = orb->string_to_object( ref );
  Account_var client = Account::_narrow( obj );
  if( CORBA::is_nil( client ) ) {
    cerr << "IOR does not refer to an Account object" << endl;
    return -1;
  }
  // Invoke operations on remote object
  client->deposit( 700 );
  client->withdraw( 250 );
  cout << "Balance is " << client->balance() << endl;


</p>
  return 0;
}

Back to Article


Copyright © 1998, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.