1. Home
  2. Tutorials
  3. C/C++
  4. CORBA
Yolinux.com Tutorial

CORBA, C++ and Linux:

This tutorial covers the use of CORBA (OmniORB), C++ and Linux for client - server processing and network programming..

CORBA Basics:

The Common Object Request Broker Architecture (CORBA) as defined by the OMG spec, allows clients to invoke operations on distributed objects (as defined by their IDL) without concern for their location, the programming language of the remote service, its OS, hardware platform (32 bit or 64 bit word size) or communications protocols (TCP/IP, IPX, FDDI, ATM,...).

CORBA is a support framework of applications, libraries and services for making distributed procedure calls. A program on computer "C" (CORBA client) calls a function which is computed and processed on computer node "S" (CORBA server) and passes to it function arguments. The function/method passes arguments and returns values as with any other C/C++ call except that it may be distributed across the network so that portions of the program may be executed on a remote machine.

CORBA's strength is that it allows platform and programming language interoperability. The interface between the client and server is defined by the CORBA IDL language which can be processed to produce code to support a variety of languages and platforms. The CORBA communication protocol, the language mappings and object model are standardized to allow this general inter-operability.

The remote function/method may start programs (fork/exec) on the remote computer or run remote services uniquely available to the remote computer and then return data.

In this example we will run a CORBA name service which acts as the glue between the client and server.

Sequence:

CORBA sequence diagram
  1. Application calls Function_1a()
  2. CORBA name service locates Function_1a() on "server 1"
  3. Application requests a call to Function_1a() on "server 1"
  4. Execution of Function_1a() on "server 1" returns a function return value and returns an argument list.

CORBA ORB's:

Various CORBA implementations are available for Linux:

  • Open Source:
    • OmniORB: C++, AT&T of England
      Small footprint and modern implementation. This ORB is covered in this tutorial.
      Debian:
      • C++: omniorb4
      • Python: python-omniorb2
    • TAO: [TheAceORb.com]: C++ based on the ACE framework
      Debian: ace
    • JACOrb: Java Implementation
    • MICO: C++
    • ORBit: Gnome desktop implementation
      Debian:
      • C: orbit2
      • C++: orbit2spp
    • Fnorb: Python
      Debian: fnorb
    The following have name services: omniORB4, ORBit2 and TAO
  • Commercial:
    • Borland Visibroker:
    • IONA Orbix:

Links:

OmniORB installation and configuration:

OmniORB is a fast and standards compliant CORBA ORB. It provides the IDL compiler which creates C++ source routines (.hh and .cc files) which one calls and links with. It also provides the CORBA libraries and include files.

OmniORB requires Packages python and python-devel 2.2 or better. The IDL compiler is written in Python.

Install from source:

Download from: sourceforge

Compile and install OmniORB:

  • tar xzf omniORB-4.X.X.tar.gz
  • cd omniORB-4.X.X
  • Configure:
    • Linux: ./configure --prefix=/opt --enable-threads --enable-shared
    • Solaris: ./configure --prefix=/opt --enable-threads --enable-shared PYTHON=/usr/local/bin/python CC=/usr/local/bin/gcc CXX=/usr/local/bin/g++
    • SGI/IRIX: ./configure --prefix=/opt --enable-threads --enable-shared PYTHON=/usr/freeware/bin/python CC=/bin/cc CXX=/bin/CC
      Note: Edit file src/lib/omniORB/orbcore/proxyFactory.CC
      Change from: To:
         if(ofl)return;
      ...
         if(!ofl)
      {
      ...
      }
  • make
  • make install
Configure flags:
  • --disable-static: speeds up build, but so static libs are produced
  • --enable-threads: Use pthreads
  • --enable-shared: default - shared libraries generated
On various platforms it may be required to specify the location of the compiler and of Python. i.e. for SGI/IRIX add CC=/usr/freeware/bin/gcc CXX=/usr/freeware/bin/g++ PYTHON=/usr/freeware/bin/python

Excellent documentation can be found in the directory: omniORB-4.X.X/doc/...

Packages:

Red Hat RPM: [download from EPEL]
rpm -ivh omniORB-4.X.X

Debian package: omniORB4 (C++)


Edit config file: /etc/omniORB.cfg

On Linux and Cygwin platforms comment out the following two directives:
  • supportPerThreadTimeOut
  • poaUniquePersistentSystemIds

CORBA ORB: OmniORB

The following steps will create an operational CORBA transaction:

  1. Server Set-up:
    • Start name service. (This will also define the IOR.) Edit /etc/omniORB.cfg and update with IOR generated by the omniNames CORBA name server.
    • Set environment variable:
          [OmniTest]$ export OMNIORB_CONFIG=/etc/omniORB.cfg
    • Start CORBA server.
  2. Remote CORBA service "A" now makes available functions/methods "A" and "B" to CORBA clients.

  3. CORBA usage:
    • Set environment variable:
          [OmniTest]$ export OMNIORB_CONFIG=/etc/omniORB.cfg
    • Run CORBA client.

CORBA name service:

OmniORB config file: omniORB.cfg (based on sample.cfg)

Generate an IOR:

  • omniNames --help
  • Generated in log file as defined during start-up:
    omniNames -start -logdir /opt/omni/omniNamesLogdir -errlog /opt/omni/omniNamesError.txt
The argument -start is used only once to generate the IOR info. Subsequent starts do not require the use of this command line argument. The OmniORB libraries must be included in existing library path or set the environment variable LD_LIBRARY_PATH:
    export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH

Use/edit URI:

  • InitRef = NameService=corbaname::my.host.name
    or
  • InitRef = NameService=IOR:01000000280000004944...
    or
  • InitRef = TradingService=corbaloc:iiop:marrow:5009/MyObjectKey
    (corbaloc)
The IOR identifies the location of the CORBA name service as identified by it's IP address and port number. A change of either will result in the requires use if a different IOR. The IOR is generated on the OmniORB name server platform by omniNames. This IOR will then used in all the omniORB.cfg files for all the CORBA client and server computer systems.

Notes:

  • The default port is 2809 which complies with OMG's COS naming service protocol.
  • One may specify the log file directory:
    • Command line argument: -logdir /opt/omni/omniNamesLogdir
      or
    • Environment variable: export OMNINAMES_LOGDIR=/opt/omni/omniNamesLogdir
CORBA IDL:

The IDL (Interface Definition Language) is a programming language neutral function/method definition and data definition language used to define the interface between the client and server. In this example we will be using C++ for both the client and server.

File: Data.idl

ifndef __DATADIST_IDL__
#define __DATADIST_IDL__
                                                                                
module Data
{
                                                                                
interface ServiceA{
   boolean CallServiceRoutineA ( in    long num1,
                                 inout long num2,
                                 out   long retNum );
   boolean CallServiceRoutineB ( inout long num1,
                                 inout long num2);
   };
};
#endif
IDL Compile: omniidl -bcxx Data.idl

This results in the generation of an include file Data.hh and a C++ source file DataSK.cc. The file DataSK.cc is to be compiled and linked with your program and provides the CORBA communications infrastructure classes and functions which are called by the application. The include file is to be included by both the CORBA client and CORBA server.


CORBA IDL Data types:

IDL C++ Description: Word size and range
short CORBA::Short 16 bit: -2^15 ... +2^15 - 1
long CORBA::Long 32 bit: -2^31 ... +2^31 - 1
long long CORBA::LongLong 64 bit: -2^63 ... +2^63 - 1
unsigned short CORBA::UShort 16 bit: 0 ... 2^16 - 1
unsigned long CORBA::ULong 32 bit: 0 ... 2^32 - 1
unsigned long long CORBA::ULongLong 64 bit: 0 ... 2^64
float CORBA::Float 32 bit IEEE single precision floating point number
double CORBA::Double 64 bit IEEE double precision floating point number
long double CORBA::LongDouble
char CORBA::Char 8 bit
wchar CORBA::WChar
(Wide Char)

string CORBA::char *
wstring CORBA::WChar *
boolean CORBA::Boolean true/false
octet CORBA::Octet (unsigned char) 8 bit raw. No conversion.
any CORBA::Any Arbitrary

CORBA Server:

This will remain the same for most CORBA servers. The only difference will be the name of the service (OmniNameService) and the implementation of the server functions/methods (CServiceA_i()).

File: Server.cpp

#include <stdlib.h>
#include <iostream>
#include <string>
#include <assert.h>
#include <signal.h>
#include <unistd.h>
                                                                                
#include "CServiceA.h"
                                                                                
#include "Data.hh"

using namespace std;
                                                                                
int main(int argc, char** argv)
{
  // --------------------------------------------------------------------------
  // Start CORBA server:
  // --------------------------------------------------------------------------
                                                                                
  try {
    //------------------------------------------------------------------------
    // 1) Initialize ORB
    // 2) Get reference to root POA
    // 3) Bind to name service
    // 4) Initialize servant object
    //------------------------------------------------------------------------
                                                                                
    //------------------------------------------------------------------------
    // Initialize CORBA ORB - "orb"
    //------------------------------------------------------------------------
    CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
                                                                                
    //------------------------------------------------------------------------
    // Servant must register with POA in order to be made available for client
    // Get reference to the RootPOA.
    //------------------------------------------------------------------------
    CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
    PortableServer::POA_var _poa = PortableServer::POA::_narrow(obj.in());
                                                                                
    //------------------------------------------------------------------------
    // Operations defined in object interface invoked via an object reference.
    // Instance of CRequestSocketStream_i servant is initialized.
    //------------------------------------------------------------------------
    CServiceA_i* myRequestServiceA = new CServiceA_i();
                                                                                
    //------------------------------------------------------------------------
    // ObjectId_var class defined in poa.h
    // typedef String_var ObjectId_var; CORBA_ORB.h
    // ???????
                                                                                
    //------------------------------------------------------------------------
    // Servant object activated in RootPOA.
    // (Object id used for various POA operations.)
    //------------------------------------------------------------------------
    PortableServer::ObjectId_var myRequestServiceA_oid
                                = _poa->activate_object(myRequestServiceA);
                                                                                
    //------------------------------------------------------------------------
    // Obtain object reference from servant and register in naming service(??)
    //------------------------------------------------------------------------
    CORBA::Object_var SA_obj = myRequestServiceA->_this();
                                                                                
    //------------------------------------------------------------------------
    // Obtain a reference to the object, and print it out as string IOR.
    //------------------------------------------------------------------------
    CORBA::String_var sior(orb->object_to_string(SA_obj.in()));
    cerr << "'" << (char*)sior << "'" << endl;
                                                                                
    //========================================================================
    // Bind (rebind) object (orb) to name (SA_obj)
    //========================================================================
                                                                                
    //------------------------------------------------------------------------
    // Bind object to name service as defined by directive InitRef
    // and identifier "OmniNameService" in config file omniORB.cfg.
    //------------------------------------------------------------------------
    CORBA::Object_var obj1=orb->resolve_initial_references("OmniNameService");
    assert(!CORBA::is_nil(obj1.in()));
                                                                                
    //------------------------------------------------------------------------
    // narrow this to the naming context
    //------------------------------------------------------------------------
    CosNaming::NamingContext_var nc = CosNaming::NamingContext::_narrow(obj1.in());
    assert(!CORBA::is_nil(nc.in()));
                                                                                
    //------------------------------------------------------------------------
    // Bind to CORBA name service. Same name to be requested by client.
    //------------------------------------------------------------------------
    CosNaming::Name name;
    name.length(1);
    name[0].id=CORBA::string_dup("DataServiceName1");
    nc->rebind (name,SA_obj.in());
                                                                                
    //========================================================================
                                                                                
    myRequestServiceA->_remove_ref();
                                                                                
    //------------------------------------------------------------------------
    // Activate the POA manager
    //------------------------------------------------------------------------
    PortableServer::POAManager_var pmgr = _poa->the_POAManager();
    pmgr->activate();
                                                                                
    //------------------------------------------------------------------------
    // Accept requests from clients
    //------------------------------------------------------------------------
    orb->run();
                                                                                
    //------------------------------------------------------------------------
    // If orb leaves event handling loop.
    // - currently configured never to time out (??)
    //------------------------------------------------------------------------
    orb->destroy();
                                                                                
    free(name[0].id); // str_dup does a malloc internally
  }
                                                                                
  catch(CORBA::SystemException&) {
    cerr << "Caught CORBA::SystemException." << endl;
  }
  catch(CORBA::Exception&) {
    cerr << "Caught CORBA::Exception." << endl;
  }
  catch(omniORB::fatalException& fe) {
    cerr << "Caught omniORB::fatalException:" << endl;
    cerr << "  file: " << fe.file() << endl;
    cerr << "  line: " << fe.line() << endl;
    cerr << "  mesg: " << fe.errmsg() << endl;
  }
  catch(...) {
    cerr << "Caught unknown exception." << endl;
  }
                                                                                
  return 0;
}

Bold text points out your customizations. The rest is cut-and-paste.

The POA (Portable Object Adapter) assists the CORBA ORB (Object Request Broker) in passing CORBA client requests to the server object implementations (servants). The POA will interpret the request, marshal the exchange of parameters then locate and activate the servant and handle error recovery and security. This allows for portable, vendor independent and extensible servant software which comply with the OMG (Object Management Group) CORBA POA specification. The POA also allows for persistence of objects so that it can support a service lifespan.

Also see: POA description.


The "servant" implementation: (denoted by "_i")

This is the routine which performs the duties of the remote service on the server.

File: CServiceA.h
#include "Data.hh"
                                                                                
class CServiceA_i :  public POA_Data::ServiceA,
                     public PortableServer::RefCountServantBase
{
public:
   CServiceA_i();
   virtual ~CServiceA_i();
   virtual CORBA::Boolean CallServiceRoutineA( CORBA::Long num1,
                                               CORBA::Long& num2,
                                               CORBA::Long& retNum);
   virtual CORBA::Boolean CallServiceRoutineB( CORBA::Long& num1,
                                               CORBA::Long& num2);
};

File: CServiceA.cpp
#include <vector>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
                                                                                
#include "CServiceA.h"
                                                                                
using namespace Data;
                                                                                
#include <sys/wait.h>
                                                                                
CServiceA_i::CServiceA_i()
{
}
                                                                                
CServiceA_i::~CServiceA_i(void)
{
}
                                                                                
CORBA::Boolean CServiceA_i::CallServiceRoutineA(
                     CORBA::Long    num1,
                     CORBA::Long&   num2,
                     CORBA::Long&   retNum)
{
                                                                                
   num2 = num2 + num1;
   retNum = 10;
                                                                                
   return true;
}
                                                                                
CORBA::Boolean CServiceA_i::CallServiceRoutineB(
                     CORBA::Long&   num1,
                     CORBA::Long&   num2)
{
                                                                                
   num1++;
   num2++;
                                                                                
   return true;
}


File: MakeServer
CC            = /usr/bin/g++
CPPFLAGS      = -g -c
LDFLAGS       = -g
OMNI_HOME     = /opt
OMNI_INCLUDES = -I$(OMNI_HOME)/include
OMNI_LIB_DIR  = $(OMNI_HOME)/lib
OMNIIDL       = $(OMNI_HOME)/bin/omniidl
INCLUDES      = $(OMNI_INCLUDES)
LIBS          = -lomniORB4 -lomnithread -lomniDynamic4
OBJECTS       = Data.o CServiceA.o Server.o
                                                                                
all Server: $(OBJECTS)
         $(CC) $(LDFLAGS) -o Server -L$(OMNI_HOME)/lib $(OBJECTS) $(LIBPATH) $(LIBS)
                                                                                
Data.o: DataSK.cc Data.hh
        $(CC) $(CPPFLAGS) $(INCLUDES) DataSK.cc
                                                                                
Server.o: Server.cpp Data.hh
        $(CC) $(CPPFLAGS) $(INCLUDES) Server.cpp
                                                                                
CServiceA.o: CServiceA.cpp CServiceA.h Data.hh
        $(CC) $(CPPFLAGS) $(INCLUDES) CServiceA.cpp
                                                                                
DataSK.cc: Data.idl
         $(OMNI_HOME)/bin/omniidl -bcxx Data.idl
                                                                                
clean clean_all:
        rm -fr *.o
        rm -fr core
        rm -fr *.hh
        rm -fr *SK.cc
        rm -fr Server
Run: make -f MakeServer

CORBA Client:

File: CRequestServiceA.h

#include <iostream>
#include <fstream>
#include "Data.hh"
                                                                                
using namespace std;
                                                                                
class CRequestServiceA {
public:
   CRequestServiceA();
   ~CRequestServiceA();
   bool RequestServiceARoutineA();
   bool RequestServiceARoutineB();
                                                                                
   CosNaming::Name m_corbaCosName;
                                                                                
   // CORBA ORB
   CORBA::ORB_var             m_orb;
                                                                                
   CORBA::Object_var          m_obj;      // ORB Object
   CORBA::Object_var          m_obj1;     // Resolved id to object reference
                                                                                
   // Resolved and narrowed CORBA object for proxy calls
   Data::ServiceA_var         m_Data;
};
                                                                                
class DS_ServerConnectionException{
public:
   DS_ServerConnectionException() { cerr << "CORBA COMM_FAILURE" << endl; };
};
                                                                                
class DS_SystemException{
public:
   DS_SystemException() { cerr << "CORBA Exception" << endl; };
};
                                                                                
class DS_FatalException{
public:
   DS_FatalException() { cerr << "CORBA Fatal Exception" << endl; };
};
                                                                                
class DS_Exception{
public:
   DS_Exception() { cerr << "Exception" << endl; };
};

File: CRequestServiceA.cpp

The constructor is fairly generic and will be edited to match the names of your name server and service names. The constructor establishes the connection with the CORBA server but does not invoke any of the remote procedures. The routines "A" and "B" are called locally but executed remotely on the CORBA server.

#include "Data.hh"
#include "CRequestServiceA.h"
using namespace Data;
                                                                                
CRequestServiceA::CRequestServiceA()
{
  try {
    //------------------------------------------------------------------------
    // Initialize ORB object.
    //------------------------------------------------------------------------
    int    argc=0;       // Dummy variables to support following call.
    char** argv=0;
    CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
                                                                                
    //------------------------------------------------------------------------
    // Bind ORB object to name service object.
    // (Reference to Name service root context.)
    //------------------------------------------------------------------------
    CORBA::Object_var obj = orb->resolve_initial_references("OmniNameService");
    assert (!CORBA::is_nil(obj.in()));
                                                                                
    //------------------------------------------------------------------------
    // Narrow this to the naming context (Narrowed reference to root context.)
    //------------------------------------------------------------------------
    CosNaming::NamingContext_var nc =
                        CosNaming::NamingContext::_narrow(obj.in());
    assert (!CORBA::is_nil(nc.in()));
                                                                                
    //------------------------------------------------------------------------
    // The "name text" put forth by CORBA server in name service.
    // This same name ("DataServiceName1") is used by the CORBA server when
    // binding to the name server (CosNaming::Name).
    //------------------------------------------------------------------------
    CosNaming::Name _corbaCosName;
    _corbaCosName.length(1);
    _corbaCosName[0].id=CORBA::string_dup("DataServiceName1");
                                                                                
    //------------------------------------------------------------------------
    // Resolve "name text" identifier to an object reference.
    //------------------------------------------------------------------------
    CORBA::Object_var obj1 = nc->resolve(_corbaCosName);
    assert(!CORBA::is_nil(obj1.in()));
                                                                                
    m_Data = ServiceA::_narrow(obj1.in());
    if (CORBA::is_nil(m_Data.in()))
    {
       cerr << "IOR is not an SA object reference." << endl;
    }
  }
  catch(CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE -- unable to contact the "
         << "object." << endl;
    throw DS_ServerConnectionException();
    return;
  }
  catch(CORBA::SystemException& ) {
    cerr << "Caught a CORBA::SystemException." << endl;
    throw DS_SystemException();
    return;
  }
  catch(CORBA::Exception& ) {
    cerr << "Caught CORBA::Exception." << endl;
    throw DS_Exception();
    return;
  }  catch(omniORB::fatalException& fe) {
    cerr << "Caught omniORB::fatalException:" << endl;
    cerr << "  file: " << fe.file() << endl;
    cerr << "  line: " << fe.line() << endl;
    cerr << "  mesg: " << fe.errmsg() << endl;
    throw DS_FatalException();
    return;
  }
  catch(...) {
    cerr << "Caught unknown exception." << endl;
    throw DS_Exception();
    return;
  }
  return;
}
                                                                                
CRequestServiceA::~CRequestServiceA()
{
   // ...
}
                                                                                
bool CRequestServiceA::RequestServiceARoutineA()
{
   CORBA::Long num1=4;
   CORBA::Long num2=5;
   CORBA::Long retNum;
                                                                                
   cout << "Values input to Service Routine A: "
        << num1 << " "
        << num2 << " "
        << retNum << endl;
                                                                                
   if( m_Data->CallServiceRoutineA( num1, num2, retNum)) // This is the CORBA call which is to be executed remotely
   {    // Ok
      cout << "Values returned by Service Routine A: "
           << num1 << " "
           << num2 << " "
           << retNum << endl;
                                                                                
      return true;
   }
   else // fail
   {
      return false;
   }
                                                                                
   return true;
}
                                                                                
bool CRequestServiceA::RequestServiceARoutineB()
{
   CORBA::Long num1=0;
   CORBA::Long num2=50;
                                                                                
   cout << "Values input to Service Routine B: "
        << num1 << " "
        << num2 << endl;
                                                                                
   if( m_Data->CallServiceRoutineB( num1, num2)) // This is the CORBA call which is to be executed remotely
   {    // Ok
      cout << "Values returned by Service Routine B: "
           << num1 << " "
           << num2 << endl;
                                                                                
      return true;
   }
   else // fail
   {
      return false;
   }
                                                                                
   return true;
}
The CORBA calls CallServiceRoutineA() and CallServiceRoutineB() will be performed on the CORBA server. The interface between client and server for these functions are defined in the IDL.

File: Client.cpp

#include "CRequestServiceA.h"
                                                                                
int main(int argc, char** argv)
{
   CRequestServiceA requestServiceA;  // Constructor establishes the link with the CORBA server.
                                                                                
   if(requestServiceA.RequestServiceARoutineA()) cout << "ServiceA RoutineA: True" << endl;
   if(requestServiceA.RequestServiceARoutineB()) cout << "ServiceA RoutineB: True" << endl;
                                                                                
   return 0;
}
This is the value of CORBA. This is why we use CORBA. Look at how simple the program looks. The constructor establishes the link with the CORBA server. The subsequent calls to Routine A and B are processed remotely on the CORBA server but called like any other local function call.


File: MakeClient

CC            = /usr/bin/g++
CPPFLAGS      = -g -c
LDFLAGS       = -g
OMNI_HOME     = /opt
OMNI_INCLUDES = -I$(OMNI_HOME)/include
OMNI_LIB_DIR  = $(OMNI_HOME)/lib
OMNIIDL       = $(OMNI_HOME)/bin/omniidl
INCLUDES      = $(OMNI_INCLUDES)
LIBS          = -lomniORB4 -lomnithread -lomniDynamic4
OBJECTS       = Data.o Client.o CRequestServiceA.o
                                                                                
all Client: $(OBJECTS)
        $(CC) $(LDFLAGS) -o Client Client.o CRequestServiceA.o Data.o $(LIBS)
                                                                                
Client.o: Client.cpp CRequestServiceA.h
        $(CC) $(CPPFLAGS) Client.cpp
                                                                                
CRequestServiceA.o: CRequestServiceA.cpp CRequestServiceA.h Data.hh
        $(CC) $(CPPFLAGS) CRequestServiceA.cpp
                                                                                
Data.o: DataSK.cc Data.hh
        $(CC) $(CPPFLAGS) DataSK.cc
                                                                                
DataSK.cc: Data.idl
        $(OMNI_HOME)/bin/omniidl -bcxx Data.idl
                                                                                
clean clean_all:
        rm -fr *.o
        rm -fr core
        rm -fr *.hh
        rm -fr *SK.cc
        rm -fr Client
Run: make -f MakeClient

Results:

Set the OMNIORB_CONFIG environment variable and then run the client:

[OmniTest]$ export OMNIORB_CONFIG=/etc/omniORB.cfg
[OmniTest]$ ./Client
omniORB: Distribution date: Sun Sep 22 22:06:56 BST 2002 dgrisby
omniORB: Initialising omniDynamic library.
omniORB: Creating ref to remote: key<0x4e616d6553657276696365>
 target id      : IDL:omg.org/CORBA/Object:1.0
 most derived id: IDL:omg.org/CosNaming/NamingContextExt:1.0
omniORB: Initial reference `OmniNameService' resolved from configuration file.
omniORB: LocateRequest to remote: key<0x4e616d6553657276696365>
omniORB: AsyncInvoker: thread id = 1 has started. Total threads = 1
omniORB: Invoke 'resolve' on remote: key<0x4e616d6553657276696365>
omniORB: Creating ref to remote: root<0>
 target id      : IDL:omg.org/CORBA/Object:1.0
 most derived id: IDL:Data/ServiceA:1.0
Values input to Service Routine A: 4 5 0
omniORB: LocateRequest to remote: root<0>
omniORB: Invoke 'CallServiceRoutineA' on remote: root<0>
Values returned by Service Routine B: 4 9 10
ServiceA RoutineA: True
Values input to Service Routine B: 0 50
omniORB: Invoke 'CallServiceRoutineB' on remote: root<0>
Values returned by Service Routine B: 1 51
ServiceA RoutineB: True

[Potential Pitfall]:

[OmniTest]$ ./Client
Caught CORBA::Exception.
Exception
Aborted

You must set your environment before running the client program:
   export OMNIORB_CONFIG=/etc/omniORB.cfg


[Potential Pitfall]: The OmniORB libraries must be included in existing library path or added for the use of the IDL compiler, running the name server, the CORBA server and the CORBA client. To set the environment variable LD_LIBRARY_PATH:

    export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH


What happened?

  • The omniNames service must be up and running first.
  • The CORBA server is started next. The server will use the environemnt variable (OMNIORB_CONFIG) to locate the config file omniORB.cfg
  • The CORBA server will use the IOR in the config file to locate the name server.
  • The CORBA server will register it's services with the name server and where to find them (IP and port)
  • CORBA client starts and uses the environemnt variable (OMNIORB_CONFIG) to locate the config file omniORB.cfg
  • The CORBA client will use the IOR in the config file to locate the name server.
  • The CORBA client will ask the name server about services it is requesting.
  • The name server will supply the client with the location of the services.
  • The CORBA client will request services from the CORBA server.

This process can be streamlined by eliminating the name service and hard coding the client with the connection details of the service. This is less flexible as the service is then tied to the IP address of a single system. All clients would have to be recompiled with the new information if the service moved.


CORBA "Sequence" data type:

A CORBA sequence is a CORBA version of a variable length one-dimensional array. Like container classes (i.e. STL vector) it allows for an array of any data type including complex data types like structures. The following are additions to the above example.


Add to file: Data.idl
 
  typedef sequence<long> NumberSeq;
   boolean CallServiceRoutineC ( inout long sum,
                                 in    NumberSeq numberList);


Add to file: CServiceA.h:

   virtual CORBA::Boolean CallServiceRoutineC( CORBA::Long& sum,
                                               const Data::NumberSeq& numberList);

Add to file: CServiceA.cpp
CORBA::Boolean CServiceA_i::CallServiceRoutineC(
                     CORBA::Long&          sum,
                     const Data::NumberSeq&  numberList)
{
   int ii;
 
   for(ii=0; ii<numberList.length(); ii++)
   {
      sum += numberList[ii];
   }
 
   return true;
}


Add to file: Client.cpp

   if(requestServiceA.RequestServiceARoutineC()) cout << "ServiceA RoutineC: True" << endl;

Add to file: CRequestServiceA.h
   bool RequestServiceARoutineC();

Add to file: CRequestServiceA.cpp
bool CRequestServiceA::RequestServiceARoutineC()
{
   CORBA::Long sum=0;
   NumberSeq numbersToAdd;
   int ii;
 
   numbersToAdd.length(4);
   numbersToAdd[0] = 10;
   numbersToAdd[1] = 20;
   numbersToAdd[2] = 30;
   numbersToAdd[3] = 40;
 
   cout << "Values input to Service Routine C: " << endl;
   for(ii=0; ii<4; ii++)
      cout << ii << ": " << numbersToAdd[ii] << endl;
 
   if( m_Data->CallServiceRoutineC( sum, numbersToAdd))
   {    // Ok
      cout << "Sum of values returned by Service Routine C: "
           << sum << endl;
 
      return true;
   }
   else // fail
   {
      return false;
   }
 
   return true;
}

Results:
Values input to Service Routine C:
0: 10
1: 20
2: 30
3: 40
omniORB: Invoke 'CallServiceRoutineC' on remote: root<0>
Sum of values returned by Service Routine C: 100
ServiceA RoutineC: True

Links:

Books:

Advanced CORBA Programming with C++
by Michi Henning, Steve Vinoski
ISBN #0201379279 Addison-Wesley Professional; 1st edition

CORBA in complete detail.

Amazon.com
Pure CORBA
by Fintan Bolton
ISBN #0672318121, Pearson Education; 1st edition

Amazon.com
Client/Server Programming with Java and CORBA
ISBN #047124578X, John Wiley & Sons; 2nd edition (March 10, 1998)

Amazon.com