What is CORBA?

The Common Object Request Broker Architecture (CORBA) is a standard framework allowing software objects to communicate with one another, no matter where they are located or who has designed them. The Object Request Broker (ORB) is the "middleware" which performs the communication. Objects may reside on the same computer, or different computers connected by a network.

CORBA provides two "modes":


Objects

The primary constructs in Object-Oriented (OO) languages are "classes". A class is a set of functions and data grouped under a unique name. Functions in a class are called "methods" to distinguish them from "standalone" functions. Data in a class are called "attributes" to distinguish them from "standalone" data.

A class is just a template for building ("constructing") objects. A real object which has been constructed is called an "instance".

OO languages support these basic object properties:


Managed, Distributed Objects

"Distributed Objects" refers to objects which reside in different processes, perhaps on the same computer or different computers on a network. In this context, each object is a "service", and "clients" make requests to them.

"Management" of objects in a distributed context means providing a mechanism which allows the same things an OO language does:


Interface vs. Implementation

An "interface" is a "software protocol" or "contract". From the developer's point of view, it is the part of your software that you "expose" - the "public" part. This is what enables other software to use yours.

The implementation is the actual code for the object.


CORBA Interfaces

In CORBA, an "interface" to an object can expose:

CORBA (or any other distributed object framework) must have knowledge of the desired interface to an object in order to perform requests on the object. The CORBA user must describe the interfaces in OMG's "Interface Definition Language" (IDL). Don't worry; it is not a big new programming language to learn - it is ONLY for describing your interfaces! In CORBA, interfaces can be grouped together in "modules." This is to avoid "namespace pollution" - that is, running out of sensible names for things!


OMA (Object Management Architecture)

CORBA's architecture looks something like this:


Object References

In CORBA, since object implementations live on servers, clients access them through "object references". An object reference maps to a specific, opaque type in a given programming language:

All object references also support a few generic operations: make a copy, release a reference (free memory, etc.), test for validity, a few others defined for specific languages where useful


Obtaining Object References

To use a CORBA object, you must posses a valid reference to it. An object reference may be obtained in one of three ways:

Believe it or not, the preferred way to obtain an object reference is the latter, which involves:

  1. On the server, obtain a reference for the desired object

  2. "Stringify" it: str = CORBA::ORB::object_to_string(ref)

  3. Somehow copy the string to the client

  4. The client then uses: ref = CORBA::ORB::string_to_object(str)

The first two steps are usually done by starting the service manually, where the service has calls to "register" itself with the object adapter, stringify the resulting reference, and print it.


Exceptions

Exceptions are objects which may be "thrown" to indicate errors. A method may be declared to throw one or more exceptions, and the caller "catches" them, providing code to handle them. Programming languages which support exceptions provide a syntax to catch exceptions which separates "normal" code from exception-handling code. This clean "separation of concerns" is the primary appeal of exceptions:


  try {

    // "normal" code goes here, and can assume that everything is fine
    // (instead of checking status at every step)

  } catch( <exception-name> <variable> ) {

    // code to handle the named exception goes here
    // the variable is set to the exception object, so code can use it

  }

CORBA exceptions come in two generic flavors:

C has no exception mechanism, so in C, all operations take a CORBA_Environment * as the last argument; a C program can check its fields for exception information (CORBA_Environment is a predefined structure).


OMG IDL

To generate static stubs and skeletons, the user defines interfaces in OMG IDL and runs an IDL compiler on them. OMG IDL borrows from C++ syntax, but makes some changes and additions. IDL Supports:


OMG IDL (con't)

IDL Data Types:

IDL uses braces to enclose scopes (module, interface), parentheses to enclose comma-separated argument lists, and allows C++-style comments.


IDL vs. C++

IDL is different from C++ in the following ways:


IDL Programming Language Mappings

IDL is academic until you learn how it maps to the programming language(s) you'll use:

IDLCC++Java
module <name> { - namespace <name> { package <name>
const <type> <name> = <value> #define <name> <value> const <type> <name> = <value> static final <type> <name> = <value>
enum <name> <list> enum <name> <list> enum <name> <list> [1]
typedef <target> <name> typedef <target> <name> typedef <target> <name> compiler looks up target
interface <name> { typedef CORBA_Object <module>_<name> (class) <name>_var, (class) <name>_ptr public interface <name>
readonly attribute <type> <name> <type> <module>_<intf>__get_<name>( CORBA_Object, CORBA_Environment *) <type> <name>() <type> <name>()
attribute <type> <name> + void <module>_<intf>__set_<name>( CORBA_Object, <type>, CORBA_Environment *) + void <name>(<type>) + void <name>(<type>)
<type> <name>( [<params>]) [raises <excs>] [context <ctxs>] <type> <module>_<interface>_<name>( CORBA_Object, [<params>,] [<ctxs>,] CORBA_Environment *) <type> <name>( [<params>] [,<ctxs>] ) [throw <excs>] <type> <name>( [<params>] [,<ctxs>] ) [throws <excs>]
longCORBA_longCORBA::Longint
string CORBA_char *CORBA::char *String
arrayarrayarrayarray
struct structstructclass with public fields
param: in <type><type><type><type>
param: out <type> <type> *<type>& <type>Holder
param: inout <type> <type> *<type>& <type>Holder

[1] enums map to Java classes with the same name, with static final int fields for enumerated values, and static final fields with instances of the class, plus utility methods to access an instance's value, and find an instance based on a numeric value.


Simple Example IDL and Mappings

The following IDL:


module CDFonline
  {
  // Also, you can put in comments like this
  interface ADMEM
    {
    // This is the detector name, like "CTC" or "COT"
    attribute string DetectorSubsystem;

    // This is the crate number within the detector, starting at 0
    attribute octet CrateNumber;

    // This method will initialize the ADMEM with the given "type",
    // returning a status code
    long Initialize( in long type );

    // This method will calibrate the ADMEM, returning a status code,
    // and filling the array "constants" with up to 8K words
    long Calibrate( out long constants[8192] );
    };
  };

Generates the following C stub signatures:


CORBA_char * CDFonline_ADMEM_DetectorSubsystem( CORBA_Object obj,
						CORBA_Environment *ev );
void CDFonline_ADMEM_DetectorSubsystem( CORBA_Object obj, CORBA_char * newval,
					CORBA_Environment *ev );

CORBA_octet CDFonline_ADMEM_CrateNumber( CORBA_Object obj,
					 CORBA_Environment *ev );
void CDFonline_ADMEM_CrateNumber( CORBA_Object obj, CORBA_octet newval,
				  CORBA_Environment *ev );

CORBA_long CDFonline_ADMEM_Initialize( CORBA_Object obj, CORBA_long type,
				       CORBA_Environment *ev );

CORBA_long CDFonline_ADMEM_Calibrate( CORBA_Object obj,
				      CORBA_long constants[8192],
				      CORBA_Environment *ev );


or the following C++ stub signatures:


in "class" CDFonline_ADMEM:

	CORBA::string DetectorSubsystem();
	void DetectorSubSystem( CORBA::string newval );
	CORBA::Octet CrateNumber();
	void CrateNumber( CORBA::Octet newval );
	CORBA::Long Initialize( CORBA::Long type );
	CORBA::Long Calibrate( CORBA::Long constants[8192] );

or the following Java stub signatures:


in package CDFonline, interface ADMEM:

	String DetectorSubsystem();
	void DetectorSubsystem( String newval );
	byte CrateNumber();
	void CrateNumber( byte newval );
	int Initialize( int type );
	int Calibrate( int constants[] );


C++ Gotchas

CORBA uses C++ features which were not even official until a couple of weeks ago and/or not supported by most compilers:

An appendix specifies alternate mappings for use when compilers do not support these features:

C++ mapping STILL changing! Latest proposed changes:

Because of the alternate mappings, most CORBA-C++ code is not portable. Because of further changes to the spec, most CORBA-C++ code will be obsolete very soon...


Example C Client


main( argc, argv )
  int argc;
  char **argv;
  {
  CDFonline_ADMEM ourADMEM;
  CORBA_Environment env;
  long status;
  long constants[8192];


  /*
   * Somehow, set ourADMEM to a valid object reference 
   */

  /* set detector to COT */
  CDFonline_ADMEM__set_DetectorSubsystem( ourADMEM, "COT" );
  .
  .
  /* do our stuff */
  status = CDFonline_ADMEM_Initialize( ourADMEM, 1, &env );
  status = CDFonline_ADMEM_Calibrate( ourADMEM, constants, &env );
  .
  .
  /* release the object reference */
  CORBA_Object_release( ourADMEM, &env );
  }


Example C++ Client


main( argc, argv )
  int argc;
  char **argv;
  {
  CDFonline::ADMEM_var ourADMEM;
  long status;
  long constants[8192];

  //
  // Somehow, set ourADMEM to a valid object reference
  //
  try
    {
    // set detector to COT
    ourADMEM->DetectorSubsystem( "COT" );
    .
    .
    // do our stuff
    status = ourADMEM->Initialize( 1 );
    status = ourADMEM->Calibrate( constants );
    .
    .
    } catch( const CORBA::Exception &exc ) {
    // handle exception
    }
  }


Example Java Client


import org.omg.CORBA.*;
import CDFonline.*;

public class CORBAtest {

  public void main( String args[] ) {

    CDFonline.ADMEM ourADMEM;
    int status;
    int constants[8192];
    //
    // Somehow, set ourADMEM to a valid object reference
    //
    try {
      // set detector to COT
      ourADMEM.DetectorSubsystem( "COT" );
      .
      .
      // do our stuff
      status = ourADMEM.Initialize( 1 );
      status = ourADMEM.Calibrate( constants );
      .
      .
      } catch( org.omg.CORBA.SystemException exc ) {
      System.out.println( "Something went wrong!" );
      }
    }
  }


Services

How does an ORB find and activate services, and invoke their methods?

This is the Object Adapter's job. CORBA currently defines only the Basic Object Adapter (BOA). The BOA provides:

Definition: "servant": a process/thread which contains one or more object implementations

BOA defines four "activation policies":

Implementor decides which policy to use.