|
Related YoLinux Tutorials:
°Software development tools
°Advanced VI
°Emacs and C/C++
°C++ Info, links
°MS/Visual C++ Practices
°C++ Memory corruption and leaks
°C++ String Class
°C++ STL vector, list
°Posix Threads
°Fork and Exec
°GDK Threads
°Clearcase Commands
°YoLinux Tutorials Index
Free Information Technology Magazine Subscriptions and Document Downloads
Free Information Technology Software and Development Magazine Subscriptions and Document Downloads
|
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.
Various CORBA implementations are available for Linux:
- Open Source:
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]
rpm -ivh omniORB-4.X.X
Debian package: omniORB4 (C++) http://packages.qa.debian.org/o/omniorb4.html
Edit config file: /etc/omniORB.cfg
-
On Linux and Cygwin platforms comment out the following two directives:
- supportPerThreadTimeOut
- poaUniquePersistentSystemIds
The following steps will create an operational CORBA transaction:
- Server Set-up:
- Remote CORBA service "A" now makes available functions/methods "A" and "B" to CORBA
clients.
- CORBA usage:
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
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 |
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
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
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.
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
|
Books: |
-
|