
- •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++
You must ensure that the type code you pass is consistent with the value already in the Any, as determined by TypeCode::equivalent. If you pass a type code that is not equivalent, type raises a BAD_TYPECODE exception.
Note that the type modifier function was added with CORBA 2.3, so this technique does not work with pre-CORBA 2.3 ORBs. (For older ORBs, there is no way to control the alias information.)
16.7.2 Testing Alias Information for Extraction from Type Any
As you saw in >Section 16.5.5, by default, extraction from an Any value succeeds if the extracted-to type matches the Any's type code as determined by equivalent, which ignores aliases.
If you want to distinguish aliases for the purposes of extraction, you must explicitly test for the required alias by testing the Any's type code:
CORBA::Any a;
// Initialize a somehow...
const char * s; if (a >>= s) {
//We have a string of some kind, get type code CORBA::TypeCode_var tc = a.type();
//See what we have...
if (tc->equal(CCS::_tc_ModelType)) {
//It's a model string...
}else if (tc->equal(CCS::_tc_Location)) {
//It's a location string...
}else {
//It's some other kind of string...
}else {
// The Any does not contain a string...
}
Using this technique, you can distinguish different aliases of the same type at the receiving end. Note that the code uses equal instead of equivalent to perform the comparison. This is essential—if this code were to call equivalent instead, all strings would be treated as model strings because equivalent ignores aliases.
16.8 Creating Type Codes Dynamically
CORBA permits you to create type codes "out of thin air"—that is, to create type codes for types whose IDL definitions were not known at compile time. Normally, you do not need to create type codes yourself. Instead, you use the type codes generated for you by
630

IT-SC book: Advanced CORBA® Programming with C++
the IDL compiler. The main reason CORBA permits dynamic creation of type codes is to support applications such as protocol bridges (for example, to dynamically translate CORBA requests into another protocol, such as CMIP). Because this capability is little used, we present only a short overview of dynamic type codes here. You can consult the CORBA specification [18] for details.
16.8.1 IDL for Type Code Creation
The operations used to create type codes dynamically are part of the ORB pseudointerface. We show the full IDL here and then show a few examples of dynamic type code creation in C++.
module CORBA { // ...
typedef string Identifier; typedef string RepositoryId;
interface IRObject { /* ... */ }; interface IDLType : IRObject { /* ... */ };
struct StructMember { Identifier name; TypeCode type; IDLType type_def;
};
typedef sequence<StructMember> StructMemberSeq;
struct UnionMember { Identifier name; any label; TypeCode type; IDLType type_def;
};
typedef sequence<UnionMember> UnionMemberSeq;
typedef sequence<Identifier> EnumMemberSeq;
interface ORB { // ...
TypeCode create_struct_tc( in RepositoryId id, in Identifier name,
in StructMemberSeq members );
TypeCode |
create_union_tc( |
|
in |
RepositoryId |
id, |
in |
Identifier |
name, |
in |
TypeCode |
discriminator_type, |
in UnionMemberSeq |
members |
|
); |
|
|
TypeCode create_enum_tc( |
||
in RepositoryId |
id, |
|
in Identifier |
name, |
631

IT-SC book: Advanced CORBA® Programming with C++
in EnumMemberSeq |
members |
); |
|
TypeCode create_alias_tc( |
|
in RepositoryId |
id, |
in Identifier |
name, |
in TypeCode |
original_type |
); |
|
TypeCode create_exception_tc( in RepositoryId id, in Identifier name,
in StructMemberSeq members );
TypeCode create_interface_tc( in RepositoryId id, in Identifier name );
TypeCode create_string_tc(
in unsigned long bound );
TypeCode |
create_wstring_tc( |
||
in unsigned long |
bound |
||
); |
|
|
|
TypeCode create_fixed_tc( |
|||
in unsigned short |
digits, |
||
in short |
scale |
||
); |
|
|
|
TypeCode create_sequence_tc( |
|||
in unsigned long |
bound, |
||
in TypeCode |
|
element_type |
|
); |
|
|
|
TypeCode create_array_tc( |
|||
in unsigned long |
length, |
||
in TypeCode |
|
element_type |
|
); |
|
|
|
TypeCode create_recursive_tc( |
|||
in RepositoryId |
id |
||
); |
|
|
|
// ... |
|
|
|
}; // ...
};
Much of this interface is self-explanatory. For each constructed IDL type, the ORB interface provides an operation to create the corresponding type code. If you consult Table 16.1 on page 696, you will find that the in parameters for all the create operations correspond to the parameters listed in the table. For example,
632

IT-SC book: Advanced CORBA® Programming with C++
create_enum_tc requires the repository ID of the type code, the name of the type, and a sequence containing the names of the enumerators.
For those parameters marked as optional in Table 16.1, it is legal to pass an empty string to the corresponding create operation.
A few of the create operations deserve further explanation.
create_struct_tc
To create the type code of a structure, we must supply the repository ID, the structure name, and sequence of type StructMemberSeq containing one element for each structure member. Each element of type StructMember provides the name and type code for the member. In addition, it contains an object reference of type IDLType in the type_def member. For type code creation, you must always set this object reference to nil. (The type_def member of the structure is for use with the Interface Repository.)
create_union_tc
As with structures, the type_def member of the corresponding UnionMember type must be set to a nil reference for type code creation.
create_recursive_tc
To create a recursive type code, we must use create_recursive_tc to create a placeholder type code. That type code is replaced with the appropriate information once it is properly embedded in its enclosing type code. Consider again the recursive structure from Section 4.7.8:
struct Node {
long value; sequence<Node> children;
};
To create the type code for a structure of type Node, we can use the following code:
CORBA::TypeCode_var placeholder
= orb->create_recursive_tc("IDL:Node:1.0");
CORBA::StructMemberSeq members; members.length(2);
members[0].name = CORBA::string_dup("value");
members[0].type = CORBA::TypeCode::_duplicate(CORBA::_tc_long); members[1].name = CORBA::string_dup("children"); members[1].type = placeholder;
CORBA::TypeCode_var struct_tc
= orb->create_struct_tc("IDL:Node:1.0", "Node", members);
You must not call operations on the recursive placeholder type code until after it is properly embedded in its enclosing type code.
633

IT-SC book: Advanced CORBA® Programming with C++
16.8.2 C++ Mapping for Type Code Creation
The C++ mapping for the create operations follows the normal rules. Rather than repeat the corresponding C++ definitions here, we show two examples to illustrate how you can create type codes for structures and unions. Creation of type codes for other types is similar.
Creating the Type Code for a Simple Structure
Again, here is the IDL for the BtData structure from the climate control system:
#pragma prefix "acme.com"
module CCS { |
|
// ... |
TempType; |
typedef short |
|
// ... |
|
interface Thermostat : Thermometer { |
|
struct BtData { |
requested; |
TempType |
|
TempType |
min_permitted; |
TempType |
max_permitted; |
string |
error_msg; |
}; |
|
// ... |
|
}; |
|
// ... |
|
}; |
|
To create a type code for this structure, we must first create type codes for the member types. Then we construct a sequence of StructMember values (one for each member) and call create_struct_tc to create the type code for the structure. Here is a code fragment that achieves this:
//
// Create an alias for short called "TempType".
//
CORBA::TypeCode_var TempType_tc; TempType_tc = orb->create_alias_tc(
"IDL:acme.com/CCS/TempType:1.0", "TempType", CORBA::_tc_short
);
//
//Create a sequence containing the definitions for the
//four structure members.
//
CORBA::StructMemberSeq mseq; mseq.length(4);
mseq[0].name = CORBA::string_dup("requested"); mseq[0].type = TempType_tc;
mseq[0].type_def = CORBA::IDLType::_nil();
634

IT-SC book: Advanced CORBA® Programming with C++
mseq[1].name = CORBA::string_dup("min_permitted"); mseq[1].type = TempType_tc;
mseq[1].type_def = CORBA::IDLType::_nil();
mseq[2].name = CORBA::string_dup("max_permitted"); mseq[2].type = TempType_tc;
mseq[2].type_def = CORBA::IDLType::_nil();
mseq[3].name = CORBA::string_dup("error_msg");
mseq[3].type = CORBA::TypeCode::_duplicate(CORBA::_tc_string); mseq[3].type_def = CORBA::IDLType::_nil();
//
// Create a type code for the BtData structure.
//
CORBA::TypeCode_var BtData_tc; BtData_tc = orb->create_struct_tc(
"IDL:acme.com/CCS/Thermostat/BtData:1.0", "BtData", mseq
);
This code is straightforward. It builds the type code starting with the TempType alias. Then it constructs the member sequence and calls create_struct_tc to create the complete type code. The type code constructed in this way is indistinguishable from the
CCS::Thermostat::_tc_BtData constant.
Note that the preceding example calls _duplicate for the assignment of the CORBA::_tc_string constant reference to get a proper deep copy. There is no need to call _duplicate for the references returned by calls to _nil because _nil duplicates the reference for us (see Section 7.11.5).
According to Table 16.1, many of the parameters passed to the create calls can be the empty string. Here is the same code example to create a type code for a BtData structure, but this time leaving all type and member names as the empty string:
//
// Create an alias for short.
//
CORBA::TypeCode_var TempType_tc;
TempType_tc = orb->create_alias_tc("", "", CORBA::_tc_short);
//
//Create a sequence containing the definitions for the
//four structure members.
//
CORBA::StructMemberSeq mseq; mseq.length(4);
mseq[0].type = TempType_tc; mseq[1].type = TempType_tc; mseq[2].type = TempType_tc;
mseq[3].type = CORBA::TypeCode::_duplicate(CORBA::_tc_string);
635

IT-SC book: Advanced CORBA® Programming with C++
//
// Create a type code for the BtData structure.
//
CORBA::TypeCode_var BtData_tc; BtData_tc = orb->create_struct_tc(
"IDL:/acme.com/CCS/Thermostat/BtData", "", mseq
);
Note that this example never initializes the name member of the StructMember structure. Instead, it relies on the default initialization of nested strings to the empty string. Neither does the code initialize the type_def members; instead, it relies on the default constructor to set the object reference member to nil.
Creating the Type Code for a Union
To create the type code for a union, we again must build the information beginning with the most nested type. Here again is the KeyType union from the climate control system:
#pragma prefix "acme.com"
module CCS {
typedef unsigned long AssetType;
typedef string |
ModelType; |
typedef short |
TempType; |
typedef string |
LocType; |
// ... |
|
interface Controller {
// ...
enum SearchCriterion { ASSET, LOCATION, MODEL }; union KeyType switch(SearchCriterion) {
case ASSET:
AssetType asset_num; case LOCATION:
LocType loc; case MODEL:
ModelType model_num; };
}; // ...
};
Following is the C++ code to create the type code for this union. Again, we hit a snag when it comes to adding the union label values: we can easily create an Any containing an enumerated value if we have linked against the IDL, but we cannot portably create such an Any if we do not have compile-time knowledge of the enumerated type. For now, we use the generated insertion operator for enumerated values, meaning that the code that
636

IT-SC book: Advanced CORBA® Programming with C++
follows is not truly generic. (Chapter 17 shows how to create Any values without compile-time knowledge of user-defined types.)
//
// Create type codes for AssetType, ModelType, and LocType.
//
CORBA::TypeCode_var AssetType_tc; AssetType_tc = orb->create_alias_tc(
"IDL:acme.com/CCS/AssetType", "AssetType", CORBA::_tc_ulong
); CORBA::TypeCode_var ModelType_tc; ModelType_tc = orb->create_alias_tc(
"IDL:acme.com/CCS/ModelType", "ModelType", CORBA::_tc_string
); CORBA::TypeCode_var LocType_tc; LocType_tc = orb->create_alias_tc(
"IDL:acme.com/CCS/LocType", "LocType", CORBA::_tc_string
);
//
// Create union member sequence.
//
CORBA::Any a; CORBA::UnionMemberSeq mem_seq; mem_seq.length(3);
a < <= CCS::Controller::ASSET; |
// Assumes IDL is known |
mem_seq[0].name = CORBA::string_dup("asset_num"); |
|
mem_seq[0].label = a; |
|
mem_seq[0].type = AssetType_tc; |
|
mem_seq[0].type_def = CORBA::IDLType::_nil(); |
|
a < <= CCS::Controller::LOCATION; |
// Assumes IDL is known |
mem_seq[1].name = CORBA::string_dup("loc"); |
|
mem_seq[1].label = a; |
|
mem_seq[1].type = LocType_tc; |
|
mem_seq[1].type_def = CORBA::IDLType::_nil(); |
|
a < <= CCS::Controller::MODEL; |
// Assumes IDL is known |
mem_seq[2].name = CORBA::string_dup("model_num"); mem_seq[2].label = a;
mem_seq[2].type = ModelType_tc; mem_seq[2].type_def = CORBA::IDLType::_nil();
//
// Create type code for SearchCriterion discriminator.
//
CORBA::EnumMemberSeq es; es.length(3);
es[0] = CORBA::string_dup("ASSET"); es[1] = CORBA::string_dup("LOCATION"); es[2] = CORBA::string_dup("MODEL");
637