
- •Advanced CORBA® Programming with C++
- •Review
- •Dedication
- •Preface
- •Prerequisites
- •Scope of this Book
- •Acknowledgments
- •Chapter 1. Introduction
- •1.1 Introduction
- •1.2 Organization of the Book
- •1.3 CORBA Version
- •1.4 Typographical Conventions
- •1.5 Source Code Examples
- •1.6 Vendor Dependencies
- •1.7 Contacting the Authors
- •Part I: Introduction to CORBA
- •Chapter 2. An Overview of CORBA
- •2.1 Introduction
- •2.2 The Object Management Group
- •2.3 Concepts and Terminology
- •2.4 CORBA Features
- •2.5 Request Invocation
- •2.6 General CORBA Application Development
- •2.7 Summary
- •Chapter 3. A Minimal CORBA Application
- •3.1 Chapter Overview
- •3.2 Writing and Compiling an IDL Definition
- •3.3 Writing and Compiling a Server
- •3.4 Writing and Compiling a Client
- •3.5 Running Client and Server
- •3.6 Summary
- •Part II: Core CORBA
- •Chapter 4. The OMG Interface Definition Language
- •4.1 Chapter Overview
- •4.2 Introduction
- •4.3 Compilation
- •4.4 Source Files
- •4.5 Lexical Rules
- •4.6 Basic IDL Types
- •4.7 User-Defined Types
- •4.8 Interfaces and Operations
- •4.9 User Exceptions
- •4.10 System Exceptions
- •4.11 System Exceptions or User Exceptions?
- •4.12 Oneway Operations
- •4.13 Contexts
- •4.14 Attributes
- •4.15 Modules
- •4.16 Forward Declarations
- •4.17 Inheritance
- •4.18 Names and Scoping
- •4.19 Repository Identifiers and pragma Directives
- •4.20 Standard Include Files
- •4.21 Recent IDL Extensions
- •4.22 Summary
- •Chapter 5. IDL for a Climate Control System
- •5.1 Chapter Overview
- •5.2 The Climate Control System
- •5.3 IDL for the Climate Control System
- •5.4 The Complete Specification
- •Chapter 6. Basic IDL-to-C++ Mapping
- •6.1 Chapter Overview
- •6.2 Introduction
- •6.3 Mapping for Identifiers
- •6.4 Mapping for Modules
- •6.5 The CORBA Module
- •6.6 Mapping for Basic Types
- •6.7 Mapping for Constants
- •6.8 Mapping for Enumerated Types
- •6.9 Variable-Length Types and _var Types
- •6.10 The String_var Wrapper Class
- •6.11 Mapping for Wide Strings
- •6.12 Mapping for Fixed-Point Types
- •6.13 Mapping for Structures
- •6.14 Mapping for Sequences
- •6.15 Mapping for Arrays
- •6.16 Mapping for Unions
- •6.17 Mapping for Recursive Structures and Unions
- •6.18 Mapping for Type Definitions
- •6.19 User-Defined Types and _var Classes
- •6.20 Summary
- •Chapter 7. Client-Side C++ Mapping
- •7.1 Chapter Overview
- •7.2 Introduction
- •7.3 Mapping for Interfaces
- •7.4 Object Reference Types
- •7.5 Life Cycle of Object References
- •7.6 Semantics of _ptr References
- •7.7 Pseudo-Objects
- •7.8 ORB Initialization
- •7.9 Initial References
- •7.10 Stringified References
- •7.11 The Object Pseudo-Interface
- •7.12 _var References
- •7.13 Mapping for Operations and Attributes
- •7.14 Parameter Passing Rules
- •7.15 Mapping for Exceptions
- •7.16 Mapping for Contexts
- •7.17 Summary
- •Chapter 8. Developing a Client for the Climate Control System
- •8.1 Chapter Overview
- •8.2 Introduction
- •8.3 Overall Client Structure
- •8.4 Included Files
- •8.5 Helper Functions
- •8.6 The main Program
- •8.7 The Complete Client Code
- •8.8 Summary
- •Chapter 9. Server-Side C++ Mapping
- •9.1 Chapter Overview
- •9.2 Introduction
- •9.3 Mapping for Interfaces
- •9.4 Servant Classes
- •9.5 Object Incarnation
- •9.6 Server main
- •9.7 Parameter Passing Rules
- •9.8 Raising Exceptions
- •9.9 Tie Classes
- •9.10 Summary
- •Chapter 10. Developing a Server for the Climate Control System
- •10.1 Chapter Overview
- •10.2 Introduction
- •10.3 The Instrument Control Protocol API
- •10.4 Designing the Thermometer Servant Class
- •10.5 Implementing the Thermometer Servant Class
- •10.6 Designing the Thermostat Servant Class
- •10.7 Implementing the Thermostat Servant Class
- •10.8 Designing the Controller Servant Class
- •10.9 Implementing the Controller Servant Class
- •10.10 Implementing the Server main Function
- •10.11 The Complete Server Code
- •10.12 Summary
- •Chapter 11. The Portable Object Adapter
- •11.1 Chapter Overview
- •11.2 Introduction
- •11.3 POA Fundamentals
- •11.4 POA Policies
- •11.5 POA Creation
- •11.6 Servant IDL Type
- •11.7 Object Creation and Activation
- •11.8 Reference, ObjectId, and Servant
- •11.9 Object Deactivation
- •11.10 Request Flow Control
- •11.11 ORB Event Handling
- •11.12 POA Activation
- •11.13 POA Destruction
- •11.14 Applying POA Policies
- •11.15 Summary
- •Chapter 12. Object Life Cycle
- •12.1 Chapter Overview
- •12.2 Introduction
- •12.3 Object Factories
- •12.4 Destroying, Copying, and Moving Objects
- •12.5 A Critique of the Life Cycle Service
- •12.6 The Evictor Pattern
- •12.7 Garbage Collection of Servants
- •12.8 Garbage Collection of CORBA Objects
- •12.9 Summary
- •Part III: CORBA Mechanisms
- •Chapter 13. GIOP, IIOP, and IORs
- •13.1 Chapter Overview
- •13.2 An Overview of GIOP
- •13.3 Common Data Representation
- •13.4 GIOP Message Formats
- •13.5 GIOP Connection Management
- •13.6 Detecting Disorderly Shutdown
- •13.7 An Overview of IIOP
- •13.8 Structure of an IOR
- •13.9 Bidirectional IIOP
- •13.10 Summary
- •14.1 Chapter Overview
- •14.2 Binding Modes
- •14.3 Direct Binding
- •14.4 Indirect Binding via an Implementation Repository
- •14.5 Migration, Reliability, Performance, and Scalability
- •14.6 Activation Modes
- •14.7 Race Conditions
- •14.8 Security Considerations
- •14.9 Summary
- •Part VI: Dynamic CORBA
- •Chapter 15 C++ Mapping for Type any
- •15.1 Chapter Overview
- •15.2 Introduction
- •15.3 Type any C++ Mapping
- •15.4 Pitfalls in Type Definitions
- •15.5 Summary
- •Chapter 16. Type Codes
- •16.1 Chapter Overview
- •16.2 Introduction
- •16.3 The TypeCode Pseudo-Object
- •16.4 C++ Mapping for the TypeCode Pseudo-Object
- •16.5 Type Code Comparisons
- •16.6 Type Code Constants
- •16.7 Type Code Comparison for Type any
- •16.8 Creating Type Codes Dynamically
- •16.9 Summary
- •Chapter 17. Type DynAny
- •17.1 Chapter Overview
- •17.2 Introduction
- •17.3 The DynAny Interface
- •17.4 C++ Mapping for DynAny
- •17.5 Using DynAny for Generic Display
- •17.6 Obtaining Type Information
- •17.7 Summary
- •Part V: CORBAservices
- •Chapter 18. The OMG Naming Service
- •18.1 Chapter Overview
- •18.2 Introduction
- •18.3 Basic Concepts
- •18.4 Structure of the Naming Service IDL
- •18.5 Semantics of Names
- •18.6 Naming Context IDL
- •18.7 Iterators
- •18.8 Pitfalls in the Naming Service
- •18.9 The Names Library
- •18.10 Naming Service Tools
- •18.11 What to Advertise
- •18.12 When to Advertise
- •18.13 Federated Naming
- •18.14 Adding Naming to the Climate Control System
- •18.15 Summary
- •Chapter 19. The OMG Trading Service
- •19.1 Chapter Overview
- •19.2 Introduction
- •19.3 Trading Concepts and Terminology
- •19.4 IDL Overview
- •19.5 The Service Type Repository
- •19.6 The Trader Interfaces
- •19.7 Exporting Service Offers
- •19.8 Withdrawing Service Offers
- •19.9 Modifying Service Offers
- •19.10 The Trader Constraint Language
- •19.11 Importing Service Offers
- •19.12 Bulk Withdrawal
- •19.13 The Admin Interface
- •19.14 Inspecting Service Offers
- •19.15 Exporting Dynamic Properties
- •19.16 Trader Federation
- •19.17 Trader Tools
- •19.18 Architectural Considerations
- •19.19 What to Advertise
- •19.20 Avoiding Duplicate Service Offers
- •19.21 Adding Trading to the Climate Control System
- •19.22 Summary
- •Chapter 20. The OMG Event Service
- •20.1 Chapter Overview
- •20.2 Introduction
- •20.3 Distributed Callbacks
- •20.4 Event Service Basics
- •20.5 Event Service Interfaces
- •20.6 Implementing Consumers and Suppliers
- •20.7 Choosing an Event Model
- •20.8 Event Service Limitations
- •20.9 Summary
- •Part VI: Power CORBA
- •Chapter 21. Multithreaded Applications
- •21.1 Chapter Overview
- •21.2 Introduction
- •21.3 Motivation for Multithreaded Programs
- •21.4 Fundamentals of Multithreaded Servers
- •21.5 Multithreading Strategies
- •21.6 Implementing a Multithreaded Server
- •21.7 Servant Activators and the Evictor Pattern
- •21.8 Summary
- •22.1 Chapter Overview
- •22.2 Introduction
- •22.3 Reducing Messaging Overhead
- •22.4 Optimizing Server Implementations
- •22.5 Federating Services
- •22.6 Improving Physical Design
- •22.7 Summary
- •Appendix A. Source Code for the ICP Simulator
- •Appendix B. CORBA Resources
- •Bibliography

IT-SC book: Advanced CORBA® Programming with C++
// show the details of each record.
static ostream &
operator<(ostream & os, const CCS::Controller::EChange & ec)
{
for (CORBA::ULong i = 0; i < ec.errors.length(); i++) {
os < "Change failed:" < endl; |
// Overloaded < |
os < ec.errors[i].tmstat_ref; |
|
os < ec.errors[i].info < endl; |
// Overloaded < |
}
return os;
}
The code iterates over the sequence contained in the exception. For each element, it calls the overloaded inserters we defined earlier to show the details and the error report for each thermostat whose set_nominal operation failed.
We need one final helper function: set_temp. This function sets the temperature of a thermostat given a reference and a new temperature. set_temp prints a number of trace messages so that we can see what is going on. If we call set_temp with an illegal temperature, its catch handler prints the details of a BadTemp exception by calling the ostream inserter we defined previously. This allows us to monitor when an exception is raised and also prevents the program from terminating by unwinding the stack all the way back to main:
// Change the temperature of a thermostat.
static void
set_temp(CCS::Thermostat_ptr tmstat, CCS::TempType new_temp)
{
if (CORBA::is_nil(tmstat)) // Don't call via nil reference return;
CCS::AssetType anum = tmstat->asset_num(); try {
cout < "Setting thermostat " < anum
<" to " < new_temp < " degrees." < endl; CCS::TempType old_nominal = tmstat->set_nominal(new_temp); cout < "Old nominal temperature was: "
<old_nominal < endl;
cout < "New nominal temperature is: "
<tmstat->get_nominal() < endl;
}catch (const CCS::Thermostat::BadTemp & bt) {
cerr |
< |
"Setting of nominal temperature failed." < endl; |
|
cerr |
< |
bt.details < endl; |
// Overloaded < |
}
}
8.6 The main Program
299

IT-SC book: Advanced CORBA® Programming with C++
The client main consists of initialization code and the code to interact with the climate control system. For this example, the client exercises the various IDL operations to test the functionality of the server.
8.6.1 Initialization
Writing the initialization code in the client is a trivial task. The first step is to initialize the ORB:
int
main(int argc, char * argv[])
{
try {
// Initialize the ORB
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
Note that orb is a _var reference so that we will correctly release the pseudo-reference returned from ORB_init.
The next step is to convert the stringified reference to the controller that is passed on the command line and to narrow it to CCS::Controller:
//Check arguments if (argc != 2) {
cerr < "Usage: client IOR_string" < endl; throw 0;
}
//Get controller reference from argv
//and convert to object.
CORBA::Object_var obj = orb->string_to_object (argv[1]); if (CORBA::is_nil(obj)) {
cerr < "Nil controller reference" < endl; throw 0;
}
// Try to narrow to CCS::Controller. CCS::Controller_var ctrl;
try {
ctrl = CCS::Controller::_narrow(obj);
} catch (const CORBA::SystemException & se) { cerr < "Cannot narrow controller reference: "
< se < endl; throw 0;
}
if (CORBA::is_nil(ctrl)) {
cerr < "Wrong type for controller ref." < endl; throw 0;
}
Note that there are two tests for nil here: one before the call to _narrow and a second one following it. If the first test fails, we know that the original stringified reference
300

IT-SC book: Advanced CORBA® Programming with C++
passed on the command line was a nil reference. If the second test fails, we know that the original reference was non-nil but that its type was not CCS::Controller.
Also note that if we detect an error here, we deal with the error condition in a catch handler and then throw zero. That causes program termination via the handler at the end of main.
8.6.2 Interacting with the Server
At this point, the client holds an active reference to the controller object and can start interacting with the server via the reference. The first step is to retrieve the complete list of devices from the controller and to show the details for each of them:
// Get list of devices CCS::Controller::ThermometerSeq_var list = ctrl->list();
//Show number of devices. CORBA::ULong len = list->length();
cout < "Controller has " < len < " device"; if (len != 1)
cout < "s"; cout < "." < endl;
//If there are no devices at all, we are finished. if (len == 0)
return 0;
//Show details for each device.
for (CORBA::ULong i = 0; i < list->length(); i++) cout < list[i];
cout < endl;
Note that the sequence of references returned from the list operation is a variablelength type, and we use the _var type for the sequence to ensure that the return value will be deallocated. The code then shows the total number of devices in the sequence on stdout. This calls the ostream inserter we defined earlier, which in turn retrieves the details of the device from the server.
The next step is to update the location attribute of whatever device happened to be returned as the first sequence element:
// Change the location of first device in the list CCS::AssetType anum = list[0]->asset_num();
cout < "Changing location of device "
<anum < "." < endl; list[0]->location("Earth");
//Check that the location was updated cout < "New details for device "
<anum < " are:" < endl;
cout < list[0] < endl;
301

IT-SC book: Advanced CORBA® Programming with C++
The statement
anum = list[0]->asset_num();
makes a remote call to read the asset number of the device, and the statement
list[0]->location("Earth");
updates the location attribute to the string "Earth". We then print the details for the first device once more so that we can see that the updated location is now returned by the server.
The next step is to change the temperature of a thermostat to a legal and then an illegal value. To do this, we must first locate a thermostat because only thermostats support a set_nominal operation:
// Find first thermostat in list. CCS::Thermostat_var tmstat;
for ( CORBA::ULong i = 0;
i < list->length() && CORBA::is_nil(tmstat); i++) {
tmstat = CCS::Thermostat::_narrow(list[i]);
}
This loop iterates over the sequence returned from list and attempts to narrow each reference on the list. The first successful narrow causes the loop to terminate, leaving the reference to the first thermostat on the list in the variable tmstat.
Provided that a thermostat was found, we now call set_nominal with a legal temperature and a second time with an illegal temperature:
// Check that we found a thermostat on the list. if (CORBA::is_nil(tmstat)) {
cout < "No thermostat devices in list." < endl;
}else {
//Set temperature of thermostat to
//50 degrees (should work).
set_temp(tmstat, 50); cout < endl;
//Set temperature of thermostat to
//-10 degrees (should fail).
set_temp(tmstat, -10);
}
In both cases, we set the temperature by calling the set_temp helper function we described on page 325. set_temp invokes set_nominal and shows either the
302

IT-SC book: Advanced CORBA® Programming with C++
updated nominal temperature (if the operation worked) or the details of a BadTemp exception (if the operation failed).
The remainder of the client exercises the Controller object. The first step is to use the find operation to look for devices in rooms Earth and HAL:
//Look for device in Rooms Earth and HAL. This must
//locate at least one device because we earlier changed
//the location of the first device to Room Earth.
cout < "Looking for devices in Earth and HAL." < endl; CCS::Controller::SearchSeq ss;
ss.length(2); ss[0].key.loc(CORBA::string_dup("Earth")); ss[1].key.loc(CORBA::string_dup("HAL")); ctrl->find(ss);
The trick here is to correctly fill in the search sequence. The search sequence contains structures that in turn are composed of a union containing a key member and a device member (recall the IDL at the end of Chapter 5). We create a local sequence variable ss, set its length to 2, and then initialize the union member of the each sequence element to the search key. The statements
ss[0].key.loc(CORBA::string_dup("Earth")); ss[1].key.loc(CORBA::string_dup("HAL"));
initialize the first two sequence elements by modifying the key members of these elements (which in turn are unions); the loc modifier method initializes the corresponding loc member. We then pass the search sequence to the find operation on the controller.
When find completes, it will have updated the passed sequence with the devices it has found (recall that the sequence is passed to find as an inout parameter). The next few lines of code show how many devices were found and the details of each device. (Because there may be more than one device in a room, the sequence may have been updated to contain more elements than it had before the call.)
// Show the devices found in that room.
for (CORBA::ULong i = 0; i < ss.length(); i++)
cout < ss[i].device; |
// Overloaded < |
cout < endl; |
|
Again, the code iterates over the sequence and prints the details of each device. The statement
cout < ss[i].device;
303

IT-SC book: Advanced CORBA® Programming with C++
prints the structure member device (which is an object reference) on stdout, so the overloaded insertion operator we defined earlier shows the details of the device.
The final step is to invoke the change operation on the controller. The change operation expects a list of references to thermostats together with a temperature delta value. This means that we must create a list containing only thermostats (of type ThermostatSeq) from the ThermometerSeq we obtained from the list operation. The easiest way to achieve this is to iterate over the polymorphic list we obtained earlier and to construct a new list that contains only thermostats:
//Increase the temperature of all thermostats
//by 40 degrees. First, make a new list (tss)
//containing only thermostats.
cout < "Increasing thermostats by 40 degrees." < endl; CCS::Controller::ThermostatSeq tss;
for (CORBA::ULong i = 0; i < list->length(); i++) { tmstat = CCS::Thermostat::_narrow(list[i]);
if (CORBA::is_nil(tmstat))
continue; // Skip thermometers len = tss.length();
tss.length(len + 1); tss[len] = tmstat;
}
This code creates a new list (tss) from the old one, using _narrow to identify those devices that are thermostats. After we have constructed this list, changing the temperature of all thermostats is trivial:
// Try to change all thermostats. try {
ctrl->change(tss, 40);
} catch (const |
CCS::Controller::EChange & ec) { |
cerr < ec; |
// Overloaded < |
}
} catch (const CORBA::Exception & e) {
cerr < "Uncaught CORBA exception: " < e < endl; return 1;
} catch (...) { return 1;
}
return 0;
}
If one or more thermostats cannot make the change because their legal temperature range is exceeded, the operation raises EChange, and we use the overloaded ostream inserter we defined earlier to show the details of the exception. This concludes the client code to exercise the climate control system.
Here is the output produced from an example run of the client:
304
|
|
IT-SC book: Advanced CORBA® Programming with C++ |
Controller has 7 |
devices. |
|
Thermometer: |
|
1027 |
Asset number: |
||
Model |
: |
Sens-A-Temp |
Location |
: |
ENIAC |
Temperature : |
67 |
|
Thermometer: |
|
2029 |
Asset number: |
||
Model |
: |
Sens-A-Temp |
Location |
: |
Deep Thought |
Temperature : |
68 |
|
Thermostat: |
|
3032 |
Asset number: |
||
Model |
: |
Select-A-Temp |
Location |
: |
Colossus |
Temperature : |
67 |
|
Nominal temp: |
68 |
|
Thermostat: |
|
4026 |
Asset number: |
||
Model |
: |
Select-A-Temp |
Location |
: |
ENIAC |
Temperature : |
58 |
|
Nominal temp: |
60 |
|
Thermostat: |
|
4088 |
Asset number: |
||
Model |
: |
Select-A-Temp |
Location |
: |
ENIAC |
Temperature : |
51 |
|
Nominal temp: |
50 |
|
Thermostat: |
|
8042 |
Asset number: |
||
Model |
: |
Select-A-Temp |
Location |
: |
HAL |
Temperature : |
40 |
|
Nominal temp: |
40 |
|
Thermometer: |
|
8053 |
Asset number: |
||
Model |
: |
Sens-A-Temp |
Location |
: |
HAL |
Temperature : |
70 |
Changing location of device 1027.
New details for device 1027 are:
Thermometer:
Asset number: 1027
Model : Sens-A-Temp
Location : Earth
Temperature : 71
Setting thermostat 3032 to 50 degrees.
Old nominal temperature was: 68
New nominal temperature is: 50
Setting thermostat 3032 to -10 degrees. Setting of nominal temperature failed. CCS::Thermostat::BtData details:
requested : -10
305