
- •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++
This problem not only exists for enumerations but also occurs if we want to extract any user-defined type without linking against the IDL-generated code for that type. We simply do not have the necessary extraction operator to get a value of user-defined type out of an Any, even though we can interrogate the Any's type code to learn about the type of the value.
In Chapter 17 we discuss how to use type DynAny to get around this limitation.
16.5 Type Code Comparisons
The show_TC function relies on being able to detect whether a particular type code was processed earlier. We detect an already-processed type code by using the STL find_if algorithm:
where = find_if(tlist.begin(), tlist.end(), EqualTypeCodes(tcp));
Here, we pass the EqualTypeCodes function object to find_if. The conversion operator to bool in EqualTypeCodes carries out type code comparison during the traversal of the container:
//
//Predicate object for find_if algorithm. Returns true
//if a type code in a container is equal to the type
//code passed to the constructor.
//
struct EqualTypeCodes { EqualTypeCodes(
CORBA::TypeCode_ptr tc ): _ptr(tc) {}
bool operator()(CORBA::TypeCode_ptr rhs) const { return _ptr->equal(rhs);
}
CORBA::TypeCode_ptr _ptr;
};
The constructor of EqualTypeCodes stores the current type code in the variable _ptr, and the conversion operator calls TypeCode::equal to compare the remembered type code against the current type during iteration.
16.5.1 Semantics of TypeCode::equal
What does it mean for two types to be equal, as determined by TypeCode::equal? Unfortunately, the answer depends on whether you are using a CORBA 2.3 ORB for the comparison and whether the type codes were created by a CORBA 2.3 or earlier ORB. The behavior of the TypeCode::equal operation is well defined in CORBA 2.3 but has implementation-dependent behavior in earlier versions (or, more bluntly, equal was underspecified before CORBA 2.3).
620

IT-SC book: Advanced CORBA® Programming with C++
For CORBA 2.3, equal performs an exact comparison and returns true only if two type codes are identical in all respects. All operations that apply for the two type codes' TCKind values must return identical results for equal to return true. Member names, type names, repository IDs, and aliases are all considered significant and must be the same.
For CORBA 2.2 and earlier, equal has implementation-dependent behavior. It may or may not consider aliases significant, and it may or may not consider type names and member names significant. (The repository ID is considered significant in all implementations we are aware of.)
The difference in behavior arises because of the parameters marked as optional in Table 16.1 on page 696. For CORBA 2.2 and earlier, repository IDs and type and member names are optional. Because of this, the outcome of a comparison with equal depends on whether or not an ORB chooses to marshal repository IDs and on whether type and member names are present in a type code. To make matters worse, the behavior of equal was never clearly defined in CORBA 2.2, so the outcome of a comparison also depends on your particular ORB implementation. The remainder of this section uses the following IDL definition to illustrate this behavior:
struct foo { long l_mem; string s_mem;
};
typedef foo alias_of_foo;
struct bar {
long long_member; string string_member;
};
Note that foo and bar are structurally equal—that is, they contain the same number and type of members in the same order—so the differences are confined to their repository IDs, type names, and member names.
Using equal in a CORBA 2.3 ORB
Assuming that both type codes were created by a CORBA 2.3 ORB, comparisons of the three types with equal in a CORBA 2.3 ORB have the following outcomes.
foo and bar are not equal.
foo and alias_of_foo are not equal. bar and alias_of_foo are not equal.
In other words, in CORBA 2.3, given CORBA 2.3 type codes, equal implements a precise comparison and requires all parameters of the two type codes to be exactly the same.
621

IT-SC book: Advanced CORBA® Programming with C++
If one or both type codes were created by a pre-CORBA 2.3 ORB, comparison of the three types with equal in a CORBA 2.3 ORB depends on how much information is present in the type codes.
If at least one of the type codes preserves the repository ID or a type or member name, equal is reliable and returns the same results as for CORBA 2.3 type codes (that is, it implements a precise comparison).
If neither type code preserves any of its optional parameters, equal uses structural comparison.
foo and bar are equal.
foo and alias_of_foo are not equal. bar and alias_of_foo are not equal.
Using equal in a CORBA 2.2 or Earlier ORB
With a CORBA 2.2 ORB, the outcome of comparisons depends on the origin of the type codes.
If both type codes were created by the same ORB, the comparison works as in CORBA 2.3 (at least in all ORB implementations we are aware of).
If the type codes were created by different ORBs, the outcome depends on the implementation of equal as well as the amount of information that is present in the type codes. This means that equal in CORBA 2.2 has implementation-dependent behavior for all three comparisons.
16.5.2 Semantics of TypeCode::equivalent
The CORBA 2.2 situation with respect to type comparison was highly unsatisfactory. Even though many applications never use type codes directly, the imprecise comparison semantics caused a number of portability and interoperability problems. To address this, CORBA 2.3 added a precise definition for equal, as explained in the preceding section. In addition, CORBA 2.3 introduced the Type-Code::equivalent operation.
The equivalent operation performs type code comparison while ignoring aliases. The operation first follows alias chains that may be present in either type code by ignoring all type codes with tk_alias; then it uses the repository IDs of the unaliased type codes to determine whether the two type codes are the same. The exact outcome depends on the origin of the type codes.
If both type codes were created by a CORBA 2.3 ORB, equivalent produces the following results.
foo and bar are not equivalent.
622

IT-SC book: Advanced CORBA® Programming with C++
foo and alias_of_foo are equivalent. bar and alias_of_foo are not equivalent.
If one or both type codes were created by a pre-CORBA 2.3 ORB, the outcome depends on how much information is carried by the type codes.
If both type codes carry repository IDs, the outcomes are as follows.
foo and bar are not equivalent.
foo and alias_of_foo are equivalent. bar and alias_of_foo are not equivalent.
If one or both type codes omit the repository ID, all three pairs of types are considered equivalent.
Intuitively, the behavior of equivalent is that it performs a comparison that ignores aliases but otherwise treats types with different names as distinct even if they are structurally equivalent. However, if the type codes do not carry a repository ID, equivalent falls back to a structural comparison.
16.5.3 Why Make Names Optional in Type Codes?
Considering the difficulty it creates, you may wonder why CORBA 2.2 allowed repository IDs and type and member names to be the empty string. The motivation for optional parameters is to save bandwidth when type codes are marshaled over the wire. For example, again consider the union from the climate control system:
union KeyType switch(SearchCriterion) { case ASSET:
AssetType asset_num; case LOCATION:
LocType loc; case MODEL:
ModelType model_num; };
The type code for this union describes the union itself and also contains the type code for the enumerated discriminator. If a type code carries a repository ID, type name, and member names, the type code for this union contains the following strings, all of which are sent over the wire:
IDL:acme.com/CCS/Controller/SearchCriterion:1.0 // Repository ID
SearchCriterion |
// Enum name |
|
ASSET |
// Enumerator |
|
LOCATION |
// Enumerator |
|
MODEL |
// Enumerator |
// Repository ID |
IDL:acme.com/CCS/Controller/KeyType:1.0 |
||
KeyType |
// Union name |
|
623

IT-SC book: Advanced CORBA® Programming with C++
asset_num |
// Member name |
loc |
// Member name |
model_num |
// Member name |
The strings for the various names consume a total of 147 bytes, not counting NUL terminators. In other words, the type code for a KeyType union is 147 bytes larger if all these names are present than if the names are empty. Considering that a value of type KeyType consists of an enumerated value for the discriminator and either a string or a number, this overhead is substantial. The type codes for unions, structures, exceptions, and enumerations suffer from this problem most often; the names account for the bulk of the size of a type code when it is marshaled. When you are sending values of type any over the wire, it can happen that the actual value in the any is only a few bytes long, whereas its associated type code consumes several hundred bytes. This problem becomes particularly noticeable when you are using complex types with the OMG Event Service (see Chapter 20), which uses type any to distribute events.
For CORBA 2.3, the repository ID is mandatory, and only type and member names can be empty. In that case, the type code for the union carries 86 bytes for its strings, still a substantial saving compared with 147 bytes.
16.5.4 Portability of Type Code Comparisons
The differences in the TypeCode interface and the different semantics of equal between CORBA 2.2 and 2.3 create a portability problem. How can you write code that reliably compares type codes with the desired semantics?
For CORBA 2.3, the answer is easy. You can use either equivalent or equal as appropriate for your application because both operations have well-defined semantics in CORBA 2.3. In addition, even with pre-CORBA 2.3 type codes, equal and equivalent perform comparisons that give the correct results in most cases. (False positives happen only if type codes do not carry a repository ID.)
For CORBA 2.2 ORBs and earlier, equivalent does not exist and equal has implementation-dependent behavior. If you do not care about stripping aliases, it is probably safe to use equal, because for all pre-CORBA 2.3 ORBs we are aware of, equal performs an exact comparison that does not ignore aliases. If you require comparisons that ignore aliases for a pre-CORBA 2.2 ORB, it is safest to write your own comparison function that first strips aliases before passing a type code to equal. (Keep in mind, though, that if an ORB omits both repository IDs and names in type codes, you can perform only a structural comparison because the information for more strict semantics is not available.)
16.5.5 Semantics of Extraction from Type any
624

IT-SC book: Advanced CORBA® Programming with C++
The semantics of type code comparison become most visible when you are extracting a value from an Any because extraction fails if a value does not match the type as which it is extracted. For CORBA 2.3 and later revisions, ORBs use equivalent to determine whether extraction should succeed. For CORBA 2.2 and earlier revisions, successful extraction depends on the (underspecified) semantics of equal.
Here is an example to illustrate this point. (Assume the IDL definitions of foo and bar on page 716.)
foo f = ...; alias_of_foo aof = ...; bar b = ...;
CORBA::Any foo_any; CORBA::Any aof_any; CORBA::Any bar_any; foo_any <= f; aof_any <= aof; bar_any <= b;
foo * foo_p; foo_any >> foo_p; aof_any >> foo_p; bar_any >> foo_p;
//Succeeds
//Succeeds in 2.3, undefined in 2.2
//Fails in 2.3, undefined in 2.2
The matching extraction succeeds in CORBA 2.3 and succeeds in all CORBA 2.2 ORBs we are aware of. The alias extraction succeeds in CORBA 2.3 and may or may not succeed in CORBA 2.2. The non-matching extraction fails in CORBA 2.3 but may or may not fail in CORBA 2.2.
Unfortunately, for your program to remain portable in CORBA 2.2 environments, your only defense is to write your own comparison operation that you can call before attempting an extraction. But keep in mind that even this approach is limited by the information that is actually present in the type codes you compare. (This becomes an issue if you receive any values from programs written using an older ORB.)
In Section 16.7 we discuss how you can explicitly test for a specific alias during extraction.
16.5.6 Structural Equivalence
Some applications require structural type equivalence. For example, it may be necessary to always treat the types foo and bar on page 716 as equivalent. Your only choice for implementing such structural equivalence is to write your own comparison function that ignores the repository ID and names in type codes and performs comparisons based purely on identical TCKind values at each nesting level.
16.5.7 The get_compact_typecode Operation
625