|
April 2000
Summary
This article discusses the interoperability of Sun Forte C++ and Gnu g++
code via CORBA. CORBA bridge enables C++ objects to be compiled using different
compilers to communicate in a distributed environment. It is a mechanism
that creates, deploys, and manages objects, referred to as CORBA components,
under a distributed environment. You can encapsulate application data and
business logic within a component that can be used in a multi-tier environment.
CORBA provides several other services, such as runtime management for objects,
component location, and life cycle management. The article focuses on a
simple procedure that allows C++ objects to interact in a "compiler independent"
manner.
Introduction
Object orientated application development using C++ is severely constrained
by compiler-imposed restrictions that essentially take away platform independence.
This is mainly due to ABI and underlying name mangling grammar differences
that are used by each compiler. Interoperability is possible only under
compiler-imposed restrictions or exception range within the linkage specifications.
However, in the case of using extern "C" linkage, it prevents mangling
of C++ methods. CORBA, as defined by OMG, provides for interoperability,
in addition to other features. The following sections illustrate the steps
that are needed to facilitate communication and method invocation in a
non-homogeneous C++ object environment.
CORBA Components
The CORBA architecture is ideal for defining, developing, and deploying
flexible distributed systems. It allows you to encapsulate application
data and business logic within a component that is used in a distributed
environment. These objects are referred to as CORBA components. Hence a
fundamental requirement for using CORBA platform is componentization of
the business logic.
Interaction among components is referred to as component collaboration.
In some cases, when you implement CORBA, you may encounter a rearchitecting
effort, such as partitioning a complex application system into smaller
components. For example, a simple client-server application fits into such
framework. However, not all applications can be easily broken down into
components. CORBA and ORB can be very useful tools to achieve interoperability
among C++ objects.
g++ and c++ Components Communicate Using ORB
This study used 2 ORBs:
The first ORB is a public domain ORB (www.mico.org). It is available
for download under gnu licensing model. You can download the entire source
to build the ORB library. Mico does not implement all the CORBA specifications.
The second ORB is a commercial ORB that comes with wider functionality.
ORBacus provides support for Sun's native compiler (WS 5.0), multithreading,
and full compliance with CORBA specifications. It is an open architecture,
and its complete source code is free for non-commercial use (http://www.ooc.com/ob).
For this article, the ORBs were built using both GNU and Sun workshop
WS 5.0 C++ compilers, and only the naming service component was included
during the build process. An important feature of CORBA is its use of IDL
(interface definition language). IDL specifies interfaces between the CORBA
components. For more details on IDL, you can refer to any book on CORBA.
Finally, OA (Object Adapter) acts as an intermediary between a component
implementation and ORB. ORB, through an OA, provides services, such as:
generating and interpreting IOR (Interoperable Object Reference), registering
objects, and invocating methods.
Back to Top
Hello Interface
The following example demonstrates the component interaction and interoperability.
It shows a single client that invokes a component remotely via a server
code, which can easily extend to multiple components (by using different
compilers).
The following code is a simple hello interface:
interface Hello
{
void hello();
};
Once you define the interface, you can use the IDL compiler to generate
the C++ files.
Implementing Hello Component
Now you have a component defined interface implemented in C++, you can
compile the component by using either gnu (g++) or the native compiler
(CC).
The following code is the Hello component implementation:
#ifdef HAVE_STD_IOSTREAM
using namespace std;
#endif
void
Hello_impl::hello()
{
count <<"Hello World"<<endl;
}
Back to Top
Instantiating Server Code
In order for the component to receive requests, you need to write a server
code to instantiate the Hello component. The server code informs the ORB
when the initialization is done.
The following is a sample server code that instantiates the Hello component;
it is ready to receive requests:
#ifdef HAVE_STD_IOSTREAM
using namespace std;
#endif
int
main(int argc, char* argv[], char*[])
{
try
{
//
// Create ORB and BOA to generate
the IOR reference files.
//
CORBA_ORB_var orb=CORBA_ORB_init(argc,
argv);
CORBA_BOA_var boa=orb->BOA_init(argc,
argv);
//
// Create implementation object
//
Hello_var p=new Hello_impl; // Hello
object instantiation
//
// Save reference. The object reference
is stringified
// and save to a file "Hello.ref"
//
CORBA_String_var s=orb->object_to_string(pP;
const char* refFile="Hello.ref";
ofstream out(refFile);
if(out.fail())
{
cerr<<argv[0]<<":can't
open `"<<refFile<<"`:"
<<strerror(errno)<<endl;
return 1;
}
out<<s<<endl;
out.close();
//
// Run implemenation - Initialization
is complete
// and the server is ready to receive
request.
//
boa->impl_is_ready(CORBA_ImplementationDef::_nil());
}
catch(CORBA_SystemException& ex)
{
OBPrintException(ex);
return 1;
}
return 0;
}
Compile the server code and the implementation by using the g++ compiler:
g++ server.cpp Hello_impl.cpp -lORBg++ -lsocket -lnsl
Back to Top
Invocating Remote Method
The following code shows a "client" code that invokes the method remotely
on the instantiated object:
try
{
//
// Create ORB
//
CORBA_ORB_var orb=CORBA_ORB_init(argc, argv);
//
// Get "hello" object
//
const char* refFile="Hello.ref";
ifstream in; // Must use open(name), not ifstream in(name)
(VC++ bug)
in.open(refFile);
if(in.fail())
{
cerr<<argv[0]<<":can't open'"<<refFile<<"':"
strerror(errno)<<endl;
return 1;
}
char s[1000];
in>>s;
CORBA_Object_var obj=orb->string_to_object(s);
assert(!CORBA_is_nil(obj));
Hello_var hello=Hello::_narrow(obj);
assert(!CORBA_is_nil(hello));
//
// Main loop
//
cout,,"Enter `h' for hello or `x' for exit:n";
char c;
do
{
count,,">";
cin>>c;
if(c=='h')
hello->hello();
}
while(c!='x');
}
catch(CORBA_SystemException& ex)
{
OBPrintException(ex);
return 1;
}
return 0;
Stringified reference file interacts between the remote caller and the
object. The CORBA method string_to_object() converts the stringified reference
to object reference. Furthermore, the remote method is invoked on the object
reference. The client side code and the associated files are compiled using
the Sun's native WorkShop 5.0 compiler:
CC Client.cpp -IORBCC -lsocket -lsnl
This example assumes that there is a shared file system on which the references
are written and invoked by the server and client. Alternatively, you can
also use the naming services provided by the ORB to execute the component
objects in a truly remote manner, which this article does not address.
Exception Handling and Other Limitations
This approach is not suitable for all applications. In cases where there
is rearchitecturing, not all algorithms can be broken down into components.
Where permissible, this approach has several advantages. When you write
smaller CORBA components, they reduce complexity and allow remote execution
and easier debugging. Finally, since C++ interfaces support exceptions,
the exceptions throw on the remote method invocation are marshalled and
sent back to the client side. You then use ORB to unmarshal the exceptions
and return it to the client. This way, the C++ handling mechanism is extended
to CORBA. This is not possible when you use other mechanisms such as specifying
extern "C" linkage that allows object mixing.
April 2000
Back to Top
|