Introducing CORBA
What is CORBA?
The wikipedia page says it all:
The Common Object Request Broker Architecture (CORBA) is a standard defined by the Object Management Group (OMG) that enables software components written in mutiple computer languages and running on multiple computers to work together (i.e., it supports mutiple platforms).
The standard was created twenty years ago, in 1991. The technology can be used in many programming languages: Python, Java, C++, C, etc.
Hence you can write a software in your favorite programming language, exposing services that others will be able to call using a different language. (Nowadays you can do the same with WebServices. This article is about CORBA.)
All CORBA specifications are available on [OMGSPEC]; latest version is [CORBA3.1].
[MCHALE] book is a very good way to learn CORBA.
How does it work?
CORBA is language agnostic because it relies on its own language: the Interface Definition Language (IDL for short). The IDL defines the contract between the client (software calling the service) and the server (software implementing the service). The service is exposed through a remote object.
IDL is used to define:
- modules, which are called namespaces in C++ (or packages in Java)
- structs, which are like C structs: they can contain data only (the data part of the contract)
- interfaces, which contain methods specification (the service part of the contract)
- exceptions that can be raised by a method
- typedefs which are type aliases
- unions, à la C
- enums, enumerations
- constants
IDL comes with existing types:
- char, octet
- string, wstring
- short, long, long long (signed if unspecified, unsigned if prefixed with unsigned)
- float, double, long double
- arrays
- sequences
- any which can be any existing or user-defined type
From this contract, the following code will be generated using a dedicated tool:
- client-side code, called stubs
- server-side code, called skeletons
So to call a CORBA remote service in a given programming language, we will generate stubs from the IDL, then write code relying on these stubs. To provide a CORBA service in a given progamming language, we will generate skeletons from the IDL, then extend them with our implementation.
The dispatching and networking machinery is handled by the Object Request Broker (ORB for short). That's the most important part of the CORBA system: it's the component that hides away remoting aspects to make distant objects appear as if they were embedded within the local, client-side code.
Telecom Log Service example
The Telecom Log Service [TLOG] is an OMG specified service that defines two interfaces:
- Log, to add, search and delete records
- LogMgr, a Log container to lookup a given log, or list all contained logs
The specification details five sub-interfaces of the log service, grouped into three different approaches:
- basic implementation. This is the service depicted below.
- event-based implementation. The Event Service [EVENT] is another CORBA service specification. Combining both services means that software emitting events can be plugged to an Event Log without modification.
- notify-based implementation. The Notification Service [NOTIF] is another CORBA service specification, built on top of the Event Service, with added filtering facility. Again, combining these two services provide easier integration with existing software.
Here is the UML representation of key base interfaces (in yellow), basic implementation (in blue) and important date structures (in green):
Here is the simplified IDL for these parts:
#include <TimeBase.idl> // IDL can include each other #pragma prefix "omg.org" // extra prefix to use in front of type names // DsLogAdmin definition // Because of the #pragma prefix above, the complete name of this module // is omg.org/DsLogAdmin module DsLogAdmin { // E X C E P T I O N -------------------------------------------------- exception InvalidGrammar {}; // empty exception exception InvalidConstraint {}; // empty exception exception LogFull { short n_records_written; }; // one attribute exception LogOffDuty {}; // empty exception exception LogLocked {}; // empty exception exception LogDisabled {}; // empty exception // T Y P E A L I A S ------------------------------------------------ typedef unsigned long LogId; typedef sequence<LogId> LogIdList; // LogIdList is a sequence of LogId typedef unsigned long long RecordId; typedef string Constraint; typedef TimeBase::TimeT TimeT; // TimeT type defined in TimeBase module typedef sequence<any> Anys; // Anys is the name of a sequence of any // S T R U C T U R E S ------------------------------------------------ struct NVPair { string name; any value; }; // <-- Mandatory semi-colon typedef sequence<NVPair> NVList; // Give a name to a sequence of NVPair struct LogRecord { RecordId id; TimeT time; NVList attr_list; any info; }; typedef sequence<LogRecord> RecordList; // I N T E R F A C E S ------------------------------------------------ // Iterator interface specification interface Iterator { // get() method: // - two input parameters // - returning a list of LogRecord // - possibly raising InvalidParam exception RecordList get(in unsigned long position, in unsigned long how_many) raises (InvalidParam); void destroy(); }; // <-- Mandatory semi-colon // Forward declaration interface LogMgr; interface Log { LogMgr my_factory(); LogId id(); // retrieve() method: // - two input parameters // - one output parameter // - returning a list of LogRecord // This method will actually return two objects: the // RecordList and the Iterator RecordList retrieve(in TimeT from_time, in long how_many, out Iterator i); RecordList query(in string grammar, in Constraint c, out Iterator i) raises (InvalidGrammar, InvalidConstraint); unsigned long delete_records(in string grammar, in Constraint c) raises (InvalidGrammar, InvalidConstraint); void write_records(in Anys records) raises (LogFull, LogOffDuty, LogLocked, LogDisabled); }; typedef sequence<Log> LogList; // Give name LogList to sequence of Log // inteface BasicLog derives from interface Log interface BasicLog : Log { void destroy(); }; interface LogMgr { LogList list_logs(); Log find_log(in LogId id); LogIdList list_logs_by_id(); }; // inteface BasicLogFactory derives from interface LogMgr interface BasicLogFactory : LogMgr { BasicLog create( in LogFullActionType full_action, in unsigned long long max_size, out LogId id) raises (InvalidLogFullAction); BasicLog create_with_id( in LogId id, in LogFullActionType full_action, in unsigned long long max_size) raises (LogIdAlreadyExists, InvalidLogFullAction); }; }; // <-- Mandatory semi-colon
The complete IDL file for the Basic Telecom Log Service is available here.
[CORBA3.1] http://www.omg.org/spec/CORBA/3.1/
[MCHALE] http://www.ciaranmchale.com/corba-explained-simply/
[OMGSPEC] http://www.omg.org/technology/documents/spec_catalog.htm#Middleware
[TLOG] http://www.omg.org/spec/TLOG/
[EVENT] http://www.omg.org/spec/EVNT/
[NOTIF] http://www.omg.org/spec/NOT/