- •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++
Type Code Parameters for Exceptions
Type codes for exceptions have the same parameters as type codes for structures. The exception name and repository ID are returned by the name and id operations.
The member_count operation returns the number of members of the exception, and the member_name and member_type operations return the name and type code of each exception member.
16.3.3 Type Codes As Values
In Section 7.7 we mention that pseudo-objects cannot be sent as parameters to IDL operations because pseudo-objects are typically implemented as library code and cannot be accessed remotely. The TypeCode pseudo-object is the only exception to this rule. It is legal to send a type code as a parameter to an IDL operation. For example:
#include <orb.idl>
interface TypeStore { exception DuplicateName {}; exception NoSuchType {};
void |
add(in string name, in CORBA::TypeCode tc) |
|
raises(DuplicateName); |
CORBA::TypeCode get(in string name) raises(NoSuchType); void remove(in string name) raises(NoSuchType);
};
The TypeStore interface maintains a table of pairs, with each pair consisting of a name and a type code. The operations allow the client to add, remove, and retrieve type codes. The TypeStore interface is fictitious; we use it here simply to illustrate that type codes are values that can be marshaled over the wire. Note that we include orb.idl in this specification. This is necessary because orb. idl contains definitions in the CORBA module, including the definition for the Type-Code interface.
CORBA intrinsically relies on the ability to marshal type codes—for example, for the transmission of any values (which contain type codes). The Interface Repository, which contains type descriptions that can be read at run time, also relies on the ability to marshal type codes as values. A number of other CORBA services, such as the Trading Service (see Chapter 19), also use type codes. For now, keep in mind that type codes are the only pseudo-object type that can be sent over the wire.
16.4 C++ Mapping for the TypeCode Pseudo-Object
Here is the C++ mapping for the TypeCode interface:
namespace CORBA { // ...
enum TCKind { tk_null, tk_void, tk_short /* , ... */ };
609
IT-SC book: Advanced CORBA® Programming with C++
class TypeCode { public:
class Bounds : public UserException { /* ...*/ }; class BadKind : public UserException { /* .. */ };
TCKind |
kind() const; |
Boolean |
equal(TypeCode_ptr tc) const; |
Boolean |
equivalent(TypeCode_ptr tc) const; |
TypeCode_ptr |
get_compact_typecode() const; |
const char * |
name() const; |
const char * |
id() const; |
ULong |
member_count() const; |
const char * |
member_name() const; |
TypeCode_ptr |
member_type(ULong index) const; |
Any * |
member_label(ULong index) const; |
TypeCode_ptr |
discriminator_type() const; |
Long |
default_index() const; |
ULong |
length() const; |
TypeCode_ptr |
content_type() const; |
UShort |
fixed_digits() const; |
UShort |
fixed_scale() const; |
}; |
|
// ... |
|
}
Note that TypeCode is a pseudo-object. Pseudo-objects can have a C++ mapping that deviates from the normal rules. In the case of the TypeCode class, strings are returned as const char * instead of as char *. This means that you must not deallocate the result of the name, id, and member_name functions; the returned pointer points at memory internal to the TypeCode instance.
The special-purpose mappings that are permissible for pseudo-objects were initially introduced to make the use of pseudo-objects easier. The idea was that if an object is known to be implemented in a library, the normal memory management rules can be relaxed to gain some efficiency and to relieve the programmer of the burden of having to remember to deallocate variable-length values.
Unfortunately, exceptions to the normal mapping rules end up making life harder instead of easier because for all operations on pseudo-objects, you must remember whether exceptions apply to each operation. After it was realized how much confusion such exceptions created, the OMG imposed a blanket ban on pseudo-objects and introduced locality-constrained objects in their place (see page 435). Locality-constrained objects are like pseudo-objects in that they are implemented in libraries, but locality-constrained objects must follow the standard mapping rules. Unfortunately, for backward
610
IT-SC book: Advanced CORBA® Programming with C++
compatibility, we are stuck with a few pseudo-objects, such as TypeCode, that have exceptions to the normal memory management rules.
Given the TypeCode mapping, we can use the type code contained in an Any value to recursively analyze the type of the value inside the Any. The show_TC function that follows illustrates how to do this. We can call show_TC as follows:
CCS::Thermostat::BtData btd;
CORBA::Any a; |
// Insert BtData value into Any a |
a < <= btd; |
CORBA::TypeCode_var tc; tc = a.type(); show_TC(tc);
// Get type code from Any a
//Print type code contents
This code produces the following output:
struct BtData (IDL:acme.com/CCS/Thermostat/BtData:1.0): requested:
typedef TempType (IDL:acme.com/CCS/TempType:1.0): short
min_permitted:
typedef TempType (IDL:acme.com/CCS/TempType:1.0): short
max_permitted:
typedef TempType (IDL:acme.com/CCS/TempType:1.0): short
error_msg: string
This output matches the IDL definition of BtData from Section 5.3.2:
#pragma prefix "acme.com"
module CCS { |
|
// ... |
TempType; |
typedef short |
|
// ... |
|
interface Thermostat : Thermometer { struct BtData {
TempType requested; TempType min_permitted; TempType max_permitted; string error_msg;
}; // ...
}; // ...
};
611
IT-SC book: Advanced CORBA® Programming with C++
The show_TC function is easy to write. To make the output more readable, show_TC indents the output according to the current level of nesting. The indent helper function prints the appropriate number of spaces at the beginning of a line:
//
// Indent to the current level.
//
const int INDENT = 4;
void
indent(int indent_lvl)
{
for (int i = 0; i <INDENT * indent_lvl; i++)
cout.put(' ');
}
show_TC is a simple function: for each possible TCKind value, it prints the parameters shown in Table 16.1. A little complexity arises because we must take care not to get trapped in an infinite loop for recursive structures and unions and must take care to show union label values correctly.
To prevent getting trapped in an infinite recursion, show_TC is overloaded as an outer and an inner version. The outer version is a wrapper function that initializes a list of type codes and then calls the inner version to do the actual work:
//
// Show the contents of a type code.
//
void show_TC(CORBA::TypeCode_ptr tcp)
{
list<CORBA::TypeCode_var> tlist; show_TC(tcp, tlist, 0);
}
The tlist variable is an STL list of type codes seen so far. The outer version of show_TC initializes tlist to an empty list and then calls the inner version of show_TC. The inner version of show_TC accepts the type code to be printed, the list of type codes seen so far, and the current indent level (set to zero on the first call and passed to indent).
The inner version of show_TC takes different actions for different type codes. Here is the first part of the source code:
//
// Show the contents of a type code. 'tcp' is the type code to
612
IT-SC book: Advanced CORBA® Programming with C++
//show, 'tlist' is the list of type codes seen so far,
//'indent_lvl' is the current nesting level. 'tlist' is used
//to prevent getting trapped in an infinite loop for recursive
//structures and unions.
//
void |
|
show_TC( |
tcp, |
CORBA::TypeCode_ptr |
|
list<CORBA::TypeCode_var> & tlist, |
|
int |
indent_lvl) |
{ |
|
static const char * const kind_name[] = { "tk_null", "void", "short", "long", "unsigned short", "unsigned long", "float", "double", "boolean", "char", "octet", "any", "CORBA::TypeCode", "CORBA::Principal", "interface", "struct", "union", "enum", "string", "sequence", "array", "typedef",
"exception", "long long", "unsigned long long", "long double", "wchar", "wstring", "fixed"
}; |
|
indent(indent_lvl); |
// Print the TCKind value. |
cout < < kind_name[tcp->kind()]; |
//
//Print name and repository ID for those type codes
//that have these parameters.
//
switch (tcp->kind()) { case CORBA::tk_objref: case CORBA::tk_struct: case CORBA::tk_union: case CORBA::tk_except: case CORBA::tk_enum: case CORBA::tk_alias:
cout < < " " < < tcp->name()
< < " (" < < tcp->id() < < "):" < < endl;
default; |
// Do nothing |
; |
|
} |
|
show_TC contains a static array that maps the TCKind enumerators to strings for printing. After calling indent to set the current indent level, show_TC prints the name of the current type, such as "struct" or "string." Type codes for object references, structures, unions, exceptions, enumerations, and type definitions contain both a name and a repository ID; the function next prints the name and repository for these type codes. Note that we do not use _var types here to deallocate the name and repository ID because the type code retains ownership of the returned strings.
The next few lines of show_TC print the parameters for non-recursive type codes:
//
613
IT-SC book: Advanced CORBA® Programming with C++
//For type codes that have other parameters,
//show the remaining parameters.
// |
|
switch (tcp->kind()) { |
// No other params to print |
default: |
|
cout < < endl; |
|
break; |
|
//
// For fixed types, show digits and scale.
//
case CORBA::tk_fixed:
cout < < "<" < < tcp->fixed_digits() < < "," < < tcp->fixed_scale() < < ">" < < endl;
break;
//
//For enumerations, show the enumerators.
case CORBA::tk_enum: indent(indent_lvl + 1);
for (CORBA::ULong i = 0; i < tcp->member_count(); i++) { cout < < tcp->member_name(i);
if (i < tcp->member_count() - 1) cout < < ", ";
}
cout < endl; break;
//For strings, show the bound (if any).
//
case CORBA::tk_string: case CORBA::tk_wstring:
{CORBA::ULong l = tcp->length();
if (l != 0)
cout < < "<" < < l < < ">"; cout < < endl;
} break;
//
// For sequences, show the bound (if any) and
//the element type.
case CORBA::tk_sequence:
{
CORBA::ULong l = tcp->length(); if (l != 0)
cout < < "<" < < l < < ">"; cout < < ":" < < endl;
CORBA::TypeCode_var etype = tcp->content_type(); show_TC(etype, tlist, indent_lvl + 1);
}
break;
//For arrays, show the dimension and element type.
//
case CORBA::tk_array:
{
CORBA::ULong l = tcp->length();
cout < < "[" < < l < < "]:" < < endl;
614
IT-SC book: Advanced CORBA® Programming with C++
CORBA::TypeCode_var etype = tcp->content_type(); show_TC(etype, tlist, indent_lvl + 1);
}
break;
//
// For typedefs, show the type of the aliased type.
//
case CORBA::tk_alias:
{
CORBA::TypeCode_var atype = tcp->content_type(); show_TC(atype, tlist, indent_lvl + 1);
}
break;
The default case at the beginning of the switch statement catches type codes that do not have parameters and terminates output with a newline character. The other branches of the switch statement call the member functions appropriate for the TCKind value of the type code according to Table 16.1.
For structures and unions, show_TC must take special action because structures and unions can be recursive. If show_TC were to simply call itself to print structure and union members, it could get trapped in a recursive loop. To avoid this, show_TC uses the list of type codes processed so far in the tlist parameter. Before descending into a structure or union member, show_TC checks whether the member's type code is already in the list. If it is not, show_TC adds the current type code to the list and decomposes it by recursing. If the type code is already in the list, show_TC shows the name and repository ID of the member's type code but does not recurse.
Here is the branch of the switch statement for structures and exceptions:
//
//For structures and exceptions, show the
//names and types of each member.
//
case CORBA::tk_struct: case CORBA::tk_except:
{
//
//Avoid a recursive loop by checking whether we
//have shown this type code before.
//
list<CORBA::TypeCode_var>::iterator where; where = find_if(
tlist.begin(), tlist.end(), EqualTypeCodes(tcp)
);
//
//If we have not seen this type code before, add it
//to the list of type codes processed so far and
//decode the member type codes.
//
if (where == tlist.end()) {
615
IT-SC book: Advanced CORBA® Programming with C++
tlist.push_back(CORBA::TypeCode::_duplicate(tcp)); for (CORBA::ULong i = 0;
i < tcp->member_count(); i++) {
cout < < tcp->member_name(i) < < ":" < < endl; indent(indent_lvl + 1);
CORBA::TypeCode_var mt = tcp->member_type(i); show_TC(mt, tlist, indent_lvl + 2);
}
} else {
cout < < " " < < tcp->name()
< < " (" < < tcp->id() < < ")" < < endl;
}
}
break;
We use the STL find_if algorithm to check whether a type code is already in the list. Because tlist is a simple list, the cost of doing this is O(n). This cost is acceptable because structures and unions rarely nest more than one or two levels, so tlist will typically contain only a few entries. The EqualTypeCodes argument to find_if is a simple function object for type code comparison (see Section 16.5).
Note that exceptions and structures are dealt with in the same branch of the switch statement. This works because exceptions are encoded the same as structures. Exceptions cannot be recursive, so the preceding code simply does not recurse for exceptions. In addition, exceptions (as opposed to structures) can be empty, in which case member_count returns zero and the code prints nothing.
The remainder of show_TC deals with unions. Unions are treated in a similar manner as structures, with tlist preventing infinite recursion. However, for unions, we also need to show the discriminator type and the case labels for each union branch:
//
//For unions, show the discriminator type.
//Then, for each member, show the case label,
//member name, and member type. To show the case
//label, we use the show_label() helper function.
case CORBA::tk_union:
{
//Avoid getting trapped in a recursive loop.
list;ltCORBA::TypeCode_var>::iterator where; where = find_if(
tlist.begin(),
tlist.end(),
EqualTypeCodes(tcp)
);
//Show the members only if we haven't shown this type
//code before.
//
616
IT-SC book: Advanced CORBA® Programming with C++
if (where == tlist.end()) { tlist.push_back(CORBA::TypeCode::_duplicate(tcp)); indent(indent_lvl + 1);
//
//Show discriminator type.
cout < < "Discriminator type:" < < endl; CORBA::TypeCode_var dt;
dt = tcp->discriminator_type(); show_TC(dt, tlist, indent_lvl + 2);
//Show case label, member name, and
//member type for each member.
//
for (CORBA::ULong i = 0;
i ;lt tcp->member_count(); i++) { CORBA::Any_var label = tcp->member_label(i); indent(indent_lvl + 1);
show_label(label); indent(indent_lvl + 2);
cout < < tcp->member_name(i) < < ":" < < endl; CORBA::TypeCode_var mt = tcp->member_type(i); show_TC(mt, tlist, indent_lvl + 3);
}
} else {
cout < < " " < < tcp->name()
< < " (" < < tcp->id() < < ")" < < endl;
}
}
break;
}
}
Note that member_label returns the value of each case label of a union as an Any. To print the label value, show_TC calls the show_label helper function. This function is mostly trivial; it extracts the type code from the passed Any to get the type of the label and extracts the value of the label according to its type using the corresponding operator>>= function:
void
show_label(const CORBA::Any * ap)
{
CORBA::TypeCode_var tc = ap->type(); if (tc->kind() == CORBA::tk_octet) { cout < < "default:" < < endl;
} else {
cout < < "case "; switch (tc->kind()) { case CORBA::tk_short:
CORBA::Short s; *ap >>= s; cout < < s; break;
617
IT-SC book: Advanced CORBA® Programming with C++
case CORBA::tk_long: CORBA::Long l; *ap >>= l;
cout < < l; break;
case CORBA::tk_ushort: CORBA::UShort us; *ap >>= us;
cout < < us; break;
case CORBA::tk_ulong: CORBA::ULong ul; *ap >>= ul;
cout < < ul; break;
case CORBA::tk_boolean: CORBA::Boolean b;
*ap >>= CORBA::Any::to_boolean(b); cout < < (b ? "TRUE" : "FALSE"); break;
case CORBA::tk_char: CORBA::Char c;
*ap >>= CORBA::Any::to_char(c); if (isalnum(c)) {
cout < < "'" < < c < < "'"; } else {
cout < < "'\\" < < setw(3) < < setfill('0') < < oct < < (unsigned)c < < "'";
}
break;
case CORBA::tk_longlong: CORBA::LongLong ll; *ap >>= ll;
cout < < ll; break;
case CORBA::tk_ulonglong: CORBA::ULongLong ull; *ap >>= ull;
cout < < ull; break;
case CORBA::tk_wchar: CORBA::WChar wc;
*ap >>= CORBA::Any::to_wchar(wc); cout < < "'" < < wc < < "'"; break;
case CORBA::tk_enum:
//Oops, problem here... We need the IDL stubs
//to extract the enumerator.
break;
default:
// Union discriminator can't be anything else abort();
}
cout < < ":" < < endl;
}
}
618
IT-SC book: Advanced CORBA® Programming with C++
Most of this code is straightforward. If the type code for a case label has a TCKind value of tk_octet, the corresponding member is the default member of the union. Otherwise, show_label extracts the label value according to the discriminator type indicated by the label's type code. Note that for discriminators of type boolean, char, and wchar, show_label uses the appropriate helper functions on CORBA::Any (to_boolean, to_char, and to_wchar) for the extraction.
One problem arises for union labels of enumerated type. Consider again the union from our climate control system:
union KeyType switch(SearchCriterion) { case ASSET:
AssetType asset_num; case LOCATION:
LocType loc; case MODEL:
ModelType model_num;
};
When show_label is used to decode the type code for a KeyType union, we hit a snag: to extract the label value, we must call an extraction operator that is over-loaded for the enumerated type. For example:
case CORBA::tk_enum: CCS::Controller::SearchCriterion sc;
*ap >>= sc; // No good break;
The problem with this is that we must have the correct overloaded operator linked into the code. This is fine for a version of show_label specifically written for the climate control system; we can simply link the code generated by the IDL compiler. However, suppose we would like to have a generic show_label function that will work for all enumerated types, even those that will be defined in the future. With the extraction functions on type Any we have seen so far, this is impossible. We could try to use the value member function of type Any to get a pointer to the raw value:
case CORBA::tk_enum: const void * val;
val = ap->value(); // No good either...
// Now what? break;
The value member returns a pointer to the value representing the enumerator. However, this does not help. The returned pointer points at data internal to the Any, and we have no idea of the binary layout of that data. (Attempts to cast the memory pointed to by val are not portable and may yield the wrong result.)
619