CORBA, OMNIORB, Asynchronous Method Invocation

AMI: Asynchronous Method Invocation under CORBA allows generation of asynchronous callback handlers and poolers.

The idl compiler generates de corresponding code to handle the responses.

1- Create a 'idl' folder and create AMIExample.idl file into it:
interface AMIExample

{
  string asyncMe(in string inputValue);
};

2- Create a compile script in the previous folder, for example idlcompile.bat:
set OMINIDL=C:\omniorb\omniORB-4.2.0\bin\x86_win32\omniidl
%OMINIDL% -bcxx -bami AmiExample.idl >> AmiExample.txt
%OMINIDL% -bcxx -Wbami AmiExample.idl

Parameter -bami AmiExample.idl >> AmiExample.txt indicates the compiler that it should create a description of the created interfaces and put it into AmiExample.txt.

After executing the compiling script AmiExample.hh,AmiexampleSK.cc and AmiExample.txt will be created into the folder.

AmiExample.txt gives a detailed definition of the available interfaces in the generated class.

// ReplyHandler for interface AMIExample
interface AMI_AMIExampleHandler : Messaging::ReplyHandler {
  void asyncMe(in string ami_return_val);
  void asyncMe_excep(in ::Messaging::ExceptionHolder excep_holder);
};

// Poller valuetype for interface AMIExample
abstract valuetype AMI_AMIExamplePoller : Messaging::Poller {
  void asyncMe(in unsigned long ami_timeout, out string ami_return_val);
};

// AMI implied operations for interface AMIExample
interface AMIExample {
  void sendc_asyncMe(in ::AMI_AMIExampleHandler ami_handler, in string inputValue);
  ::AMI_AMIExamplePoller sendp_asyncMe(in string inputValue);
};

In this example we will focus on a Callback handler, a client will perform an asynchronous method call on the servant and the response will be received (asynchronously) by a callback handler:

We need:

  • A Servant of type AMIExample
  • A Client 
  • A Handler of type AMIExampleHandler

Coding the Servant (Project A):

AmiExampleImpl:
HPP

#pragma once

#include "idl/AmiExample.hh"
#include <iostream>
#include <fstream>
using namespace std;


class AmiExampleImpl : public POA_AMIExample
{
public:
 AmiExampleImpl(void);
 virtual ~AmiExampleImpl(void);

 virtual char *asyncMe(const char *);
 
};
CPP
#include "StdAfx.h"
#include "AmiExampleImpl.hh"
#include <iostream>
#include <fstream>
#include <sstream>
#include <assert.h>


AmiExampleImpl::AmiExampleImpl(void)
{
}


AmiExampleImpl::~AmiExampleImpl(void)
{
}

char * AmiExampleImpl::asyncMe(const char *str)
{
 CORBA::string_dup(str);
}

The Servant Launcher:

CPP
#include "stdafx.h"
#include "idl/AmiExample.hh"
#include "AmiExampleImpl.hh"
#include <iostream>
#include <fstream>
#include <assert.h>

using namespace std;

int main(int argc, char** argv)
{
 const char *servantName="AMIExample";
 // --------------------------------------------------------------------------
 // Start CORBA server:
 // --------------------------------------------------------------------------
 cout<<"Welcome, initialising CORBA"<<endl;                                                                             
 try {
  //------------------------------------------------------------------------
  // 1) Initialize ORB
  // 2) Get reference to root POA
  // 3) Bind to name service
  // 4) Initialize servant object
  //------------------------------------------------------------------------

  //------------------------------------------------------------------------
  // Initialize CORBA ORB - "orb"
  //------------------------------------------------------------------------

  cout<<"Corab Servant Initialising Arguments:"<<endl;
  for (int i=0;i<argc;i++)
  {
   cout<<argv[i]<<endl;
  }
  cout<<"--------------------------------------"<<endl;
  CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); 
  cout<<"Corba initialised"<<endl;                                                                            
  //------------------------------------------------------------------------
  // 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());
  cout<<"Servant Registered"<<endl;                                                                             
  //------------------------------------------------------------------------
  // Operations defined in object interface invoked via an object reference.
  // Instance of CRequestSocketStream_i servant is initialized.
  //------------------------------------------------------------------------
  AmiExampleImpl* myService = new AmiExampleImpl;
  cout<<"Interface implementation created"<<endl;                                                                             
  //------------------------------------------------------------------------
  // 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 myservice_oid
   = _poa->activate_object(myService);
  cout<<"POA Activated"<<endl;                                                                             
  //------------------------------------------------------------------------
  // Obtain object reference from servant and register in naming service(??)
  //------------------------------------------------------------------------
  CORBA::Object_var SA_obj = myService->_this();
  cout<<"Reference to servant obtained"<<endl;                                                                              
  //------------------------------------------------------------------------
  // 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;
  cout<<"IOR Obtained"<<endl;                                                                              
  //========================================================================
  // Bind (rebind) object (orb) to name (SA_obj)
  //========================================================================

  //------------------------------------------------------------------------
  // Bind object to name service as defined by directive InitRef
  // and identifier "NameService" in config file omniORB.cfg.
  //------------------------------------------------------------------------
  cout<<"--------->Binding to name service"<<endl;
  CORBA::Object_var initServ=orb->resolve_initial_references("NameService");
  if (!CORBA::is_nil(initServ)) {
   cout<<"NameService found"<<endl;    
  } else
  {
   cout<<"NameService not found"<<endl;
  }
  assert(!CORBA::is_nil(initServ));

  //------------------------------------------------------------------------
  // narrow this to the naming context
  //------------------------------------------------------------------------
  cout<<"Narrowing Name Context"<<endl; 
  CosNaming::NamingContext_var rootContext;
  rootContext = CosNaming::NamingContext::_narrow(initServ);
  cout<<"Narrow"<<endl;
  assert(!CORBA::is_nil(rootContext));
  cout<<"Narrowing was suscessfull"<<endl;                                                                              
  //------------------------------------------------------------------------
  // Bind to CORBA name service. Same name to be requested by client.
  //------------------------------------------------------------------------
  cout<<"Binding"<<endl; 
  CosNaming::Name name;
  name.length(1);
  name[0].id=CORBA::string_dup(servantName);
  rootContext->rebind (name,SA_obj.in());
  cout<<"Bound as"<<servantName<<endl;                                                                              
  //========================================================================

  myService->_remove_ref();

  //------------------------------------------------------------------------
  // Activate the POA manager
  //------------------------------------------------------------------------
  PortableServer::POAManager_var pmgr = _poa->the_POAManager();
  pmgr->activate();
  cout<<"POA Activated"<<endl;                                                                            
  //------------------------------------------------------------------------
  // Accept requests from clients
  //------------------------------------------------------------------------
  cout<<"Accepting requests from clients"<<endl;
  orb->run(); //this is a blocking call

  //------------------------------------------------------------------------
  // If orb leaves event handling loop.
  // - currently configured never to time out (??)
  //------------------------------------------------------------------------
  orb->destroy();
  cout<<"Servant destroyed"<<endl;                                                                           
  free(name[0].id); // str_dup does a malloc internally
  getchar();
 }

 catch(CORBA::SystemException&) {
  cerr << "Caught CORBA::SystemException." << endl;
  getchar();
 }
 catch(CORBA::Exception&) {
  cerr << "Caught CORBA::Exception." << endl;
  getchar();
 }
 catch(omniORB::fatalException& fe) {
  cerr << "Caught omniORB::fatalException:" << endl;
  cerr << "  file: " << fe.file() << endl;
  cerr << "  line: " << fe.line() << endl;
  cerr << "  mesg: " << fe.errmsg() << endl;
  getchar();
 }
 catch(...) {
  cerr << "Caught unknown exception." << endl;
  getchar();
 }

 return 0;
}

Coding the Client and the Handler (Project B):

Client:
HPP
#pragma once

#include <iostream>
#include <fstream>
#include "idl/AmiExample.hh"

class CorbaAMIClient
{
public:
 CorbaAMIClient(void);
 CorbaAMIClient(CORBA::ORB_ptr orb);
 virtual ~CorbaAMIClient(void);


 // CORBA ORB
 CORBA::ORB_var m_orb;
 CORBA::Object_var m_nameService;
 CosNaming::Name m_corbaCosName;
 CosNaming::NamingContext_var m_nameContext;

 CORBA::Object_var   m_corbaref;     // Resolved id to object reference                                                                               
 // Resolved and narrowed CORBA object for proxy calls
 AMIExampleRef   m_remoteInterface;
};

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; };
};  

CPP
#include "stdafx.h"
#include "idl/AmiExample.hh"
#include "AmiExampleHandlerImpl.hh"
#include "AmiExampleHandlerImpl.hh"
#include <iostream>
#include <fstream>
#include <assert.h>
#include "CorbaAMIClient.hh"

using namespace std;



CorbaAMIClient::CorbaAMIClient(void)
{
}


CorbaAMIClient::~CorbaAMIClient(void)
{
}

CorbaAMIClient::CorbaAMIClient(CORBA::ORB_ptr orb)
{
 const char *servantName="AMIExample";
  try {
 
 /*
 cout<<"Corba Client Initialising Arguments:"<<endl;
    for (int i=0;i<argc;i++)
 {
  cout<<argv[i]<<endl;
 }*/
 m_orb=orb;
 
 cout<<"--------------------------------------"<<endl;
    //------------------------------------------------------------------------
    // Initialize ORB object.
    //------------------------------------------------------------------------
    //int    argc=0;       // Dummy variables to support following call.
    //char** argv=0;
    //CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
  /*this->m_orb= CORBA::ORB_init(argc, argv);
    cout<<"orb inited"<<endl; */                                                    
    //------------------------------------------------------------------------
    // Bind ORB object to name service object.
    // (Reference to Name service root context.)
    //------------------------------------------------------------------------
 cout<<"getting name service"<<endl; 
    //CORBA::Object_var obj = orb->resolve_initial_references("NameService");
 this->m_nameService = this->m_orb->resolve_initial_references("NameService");
 assert (!CORBA::is_nil(this->m_nameService.in()));
                                                                                
    //------------------------------------------------------------------------
    // Narrow this to the naming context (Narrowed reference to root context.)
    //------------------------------------------------------------------------
 cout<<"Narrowing"<<endl; 
    //CosNaming::NamingContext_var nc =
    //                    CosNaming::NamingContext::_narrow(obj.in());
 this->m_nameContext =  CosNaming::NamingContext::_narrow(this->m_nameService.in());
 assert (!CORBA::is_nil(this->m_nameContext));
    cout<<"narrow done"<<endl; 
                                                                                
    //------------------------------------------------------------------------
    // 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).
    //------------------------------------------------------------------------
    cout<<"binding to "<<servantName<<endl; 
    
 /*CosNaming::Name _corbaCosName;
    _corbaCosName.length(1);
    _corbaCosName[0].id=CORBA::string_dup("Dummy1");*/
 this->m_corbaCosName.length(1);
 this->m_corbaCosName[0].id=CORBA::string_dup(servantName);
                                                                                
    //------------------------------------------------------------------------
    // Resolve "name text" identifier to an object reference.
    //------------------------------------------------------------------------
 cout<<"Resolving "<<servantName<<endl; 
    //CORBA::Object_var obj1 = nc->resolve(_corbaCosName);
 this->m_corbaref= this->m_nameContext->resolve(this->m_corbaCosName);
    assert(!CORBA::is_nil(this->m_corbaref));
    cout<<"narrowing AMIExample"<<endl; 
 
 
 this->m_remoteInterface= AMIExample::_narrow(this->m_corbaref.in());

    if (CORBA::is_nil(this->m_remoteInterface))
    {
       cerr << "IOR is not an SA object reference." << endl;
    }

 cout<<servantName<<" Client prepared."<<endl;

 
 
  }
  catch(CORBA::COMM_FAILURE& ) {
    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;
}

Callback Handler:
HPP
#pragma once

#include "idl/AmiExample.hh"
#include <iostream>
#include <fstream>
using namespace std;


class AmiExampleHandlerImpl : public virtual POA_AMI_AMIExampleHandler
{
public:
 AmiExampleHandlerImpl(void);
 virtual ~AmiExampleHandlerImpl(void);

 void asyncMe(const char* ami_return_val);
 void asyncMe_excep(::Messaging::ExceptionHolder* excep_holder);

};
CPP
#include <fstream>
#include <sstream>
#include <assert.h>
#include "AmiExampleHandlerImpl.hh"

AmiExampleHandlerImpl::AmiExampleHandlerImpl(void)
{
}


AmiExampleHandlerImpl::~AmiExampleHandlerImpl(void)
{
}

void AmiExampleHandlerImpl::asyncMe(const char* ami_return_val)
{
 std::cout<<ami_return_val<<"!!!"<<std::endl;
}


void AmiExampleHandlerImpl::asyncMe_excep(::Messaging::ExceptionHolder* excep_holder)
{
 try {
  excep_holder->raise_exception();
 }
 catch (CORBA::Exception& ex) {
  cout << "echoString exception: " << ex._name() << endl;
 }
}
Client Launcher:
CPP
int main(int argc, char** argv)
{
 CORBA::ORB_ptr orb= CORBA::ORB_init(argc, argv);
 // Resolve and activate the Root POA
 // Without it, creating Handlers will FAIL!
 CORBA::Object_var poa_obj = orb->resolve_initial_references("RootPOA");
 PortableServer::POA_var poa = PortableServer::POA::_narrow(poa_obj);
 PortableServer::POAManager_var pman = poa->the_POAManager();
 pman->activate();

 //Create the callback Handler
 AMI_AMIExampleHandler_ptr handler_ptr =  (new AmiExampleHandlerImpl())->_this();

 cout<<"Welcome, initialising CORBA CLIENT"<<endl;  
 CorbaAMIClient client(orb);

 client.m_remoteInterface->sendc_asyncMe(handler_ptr,"HELLO WORLD");

 // Wait for a while -- the call should complete within this time
 omni_thread::sleep(2);
 getchar();
 PortableServer::ObjectId *oid = poa->reference_to_id(handler_ptr);
 poa->deactivate_object(*oid);
 poa->destroy(false,false);
 
 pman->deactivate(false,false);
 orb->destroy();
 return 0;
}

Results: 

The client invokes the servant asynchronously:
sendc_asyncMe(handler_ptr,"HELLO WORLD!!!");

The servant return "Hello World"  so that it is received asynchronously by the Handler:

void AmiExampleHandlerImpl::asyncMe(const char* ami_return_val)
{
 std::cout<<ami_return_val<<"!!!"<<std::endl;
}

The callback handler adds three exclamation marks to the response and "Hello World!!!" is shown in the standard output.

Code:
https://dl.dropboxusercontent.com/u/23142124/Visual%20Studio%202010%20C%2B%2B%20CORBA%20with%20OmniOrb%20and%20Java%20ORBD/AMI/CorbaAMIVS2010.zip

Ramon Talavera.

Comments

Popular posts from this blog

Qt Signals and Slots, Connecting and Disconnecting

Vaadin 7: Detect Enter Key in a TextField

JAVA JPA WITH HIBERNATE AND H2 Tutorial