- •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++
There is no sensible mapping of reopened modules onto classes. This means that IDL compilers will not permit you to reopen an IDL module if code generation is for a C++ compiler that does not support namespaces.
For the remainder of this book, we use the mapping to namespaces.
6.5 The CORBA Module
CORBA defines a number of standard IDL types and interfaces. To avoid polluting the global namespace, these definitions are provided inside the CORBA module. The CORBA module is mapped in the same way as any other module, so the ORB header files provide a CORBA namespace containing the corresponding C++ definitions.
We discuss the contents of the CORBA namespace incrementally throughout this book.
6.6 Mapping for Basic Types
IDL basic types are mapped as shown in Table 6.1. Except for string, each IDL type is mapped to a type definition in the CORBA namespace. The type definitions allow the mapping to maintain the size guarantees provided by IDL. To ensure that your code remains portable, always use the names defined in the CORBA namespace for IDL types (for example, use CORBA::Long instead of long to declare a variable). This will also help the transition of your code to 64-bit architectures (which may define
CORBA::Long as int).
Note that IDL string is mapped directly to char * instead of a type definition. The reason is that when the OMG first produced the C++ mapping, it was felt that binary layout of data in memory had to be the same for both the C and the C++ mappings.[1] This precludes mapping strings to something more convenient, such as a string class.
[1] In hindsight, imposing this restriction was probably a mistake because it forces the C++ mapping to be less type-safe and convenient than it could have been otherwise.
6.6.1 64-bit Integer and long double Types
The specification assumes that the underlying C++ implementation provides native support for (unsigned) long long and long double. If such support is not available, the mapping for these types is not specified. For that reason, you should avoid 64-bit integers and long double unless you are sure that they are supported as native C++ types on the platforms relevant to you.
|
Table 6.1. Mapping for basic types. |
|
IDL |
|
C++ |
short |
|
CORBA::Short |
long |
|
CORBA::Long |
long long |
|
CORBA::LongLong |
135
IT-SC book: Advanced CORBA® Programming with C++
unsigned short |
CORBA::UShort |
unsigned long |
CORBA::ULong |
unsigned long long |
CORBA::ULongLong |
float |
CORBA::Float |
double |
CORBA::Double |
long double |
CORBA::LongDouble |
char |
CORBA::Char |
wchar |
CORBA::WChar |
string |
char * |
wstring |
CORBA::WChar * |
boolean |
CORBA::Boolean |
octet |
CORBA::Octet |
any |
CORBA::Any |
6.6.2 Overloading on Basic Types
All the basic types are mapped so that they are distinguishable for the purposes of C++ overloading; the exceptions are char, boolean, octet, and wchar. This is because all three of the types char, boolean, and octet may map to the same C++ character type, and wchar may map to one of the C++ integer types or wchar_t. For example:
void foo(CORBA::Short param) void foo(CORBA::Long param) void foo(CORBA::Char param) void foo(CORBA::Boolean param) void foo(CORBA::Octet param) void foo(CORBA::WChar param)
{ /*...*/ }; { /*...*/ }; { /*...*/ }; { /*...*/ }; { /*...*/ }; { /*...*/ };
//May not compile
//May not compile
//May not compile
The first three definitions of foo are guaranteed to work, but the final three definitions may not compile in some implementations. For example, an ORB could map IDL char, boolean, and octet to C++ char and map IDL wchar to C++ short. (In that case, the preceding definitions are ambiguous and will be rejected by the compiler.) To keep your code portable, do not overload functions solely on Char, Boolean, and Octet, and do not overload on WChar and an integer type even if it happens to work for your particular ORB.
6.6.3 Types Mappable to char
IDL char, boolean, and octet may map to signed, unsigned, or plain char. To keep your code portable, do not make assumptions in your code about whether these types are signed or unsigned.
6.6.4 Mapping for wchar
136
IT-SC book: Advanced CORBA® Programming with C++
IDL wchar may map to a C++ integer type, such as int, or may map to C++ wchar_t. The mapping to integer types accommodates non-standard compilers, in which wchar_t is not a distinct type.
6.6.5 Boolean Mapping
On standard C++ compilers, IDL boolean may be mapped to C++ bool; the specification permits this but does not require it. If it is not mapped to C++ bool—for example, on classic C++ compilers—CORBA::Boolean maps to plain char, signed char, or unsigned char.
The C++ mapping does not require Boolean constants TRUE and FALSE (or true and false) to be provided (although true and false will work in a standard C++ environment). To keep your code portable, simply use the integer constants 1 and 0 as Boolean values; this works in both standard and classic environments.
6.6.6 String and Wide String Mapping
Strings are mapped to char *, and wide strings are mapped to CORBA::wchar *. This is true whether you use bounded or unbounded strings. If bounded strings are used, the mapping places the burden of enforcing the bound on the programmer. It is unspecified what should happen if the length of a bounded string is exceeded at run time, so you must assume that the behavior is undefined.
The use of new and delete for dynamic allocation of strings is not portable. Instead, you must use helper functions in the CORBA namespace:
namespace CORBA { |
|
// ... |
string_alloc(ULong len); |
static char * |
|
static char * |
string_dup(const char *); |
static void |
string_free(char *); |
static wchar * |
wstring_alloc(ULong len); |
static wchar * |
wstring_dup(const wchar *); |
static void |
wstring_free(wchar *); |
// ... |
|
} |
|
These functions handle dynamic memory for strings and wide strings. The C++ mapping requires that you use these helper functions to avoid replacing global operator new[] and operator delete[] and because non-uniform memory architectures may have special requirements. Under Windows, for example, memory allocated by a dynamic library must be deallocated by that same library. The string allocation functions ensure that the correct memory management activities can take place. For uniform memory models, such as in UNIX, string_alloc and string_free are usually implemented in terms of new[] and delete[].
137
IT-SC book: Advanced CORBA® Programming with C++
The string_alloc function allocates one more byte than requested by the len parameter, so the following code is correct:
char * p = CORBA::string_alloc(5); |
// |
Allocates 6 |
bytes |
strcpy(p, "Hello"); |
// |
OK, "Hello" |
fits |
The preceding code is more easily written using string_dup, which combines the allocation and copy:
char * p = CORBA::string_dup("Hello");
Both string_alloc and string_dup return a null pointer if allocation fails. They do not throw a bad_alloc exception or a CORBA exception.
The string_free function must be used to free memory allocated with string_alloc or string_dup. Calling string_free for a null pointer is safe and does nothing.
Do not use delete or delete[] to deallocate memory allocated with string_alloc or string_dup. Similarly, do not use string_free to deallocate memory allocated with new or new[]. Doing so results in undefined behavior.
The wstring* helper functions have the same semantics as the string* helper functions, but they operate on wide strings. As with string_alloc, wstring_alloc allocates an additional character to hold the zero terminating value.
6.7 Mapping for Constants
Global IDL constants map to file-scope C++ constants, and IDL constants nested inside an interface map to static class-scope C++ constants. For example:
const long MAX_ENTRIES = 10; interface NameList {
const long MAX_NAMES = 20;
};
This maps to
const CORBA::Long MAX_ENTRIES = 10; class NameList {
public:
static const CORBA::Long MAX_NAMES; // Classic or standard C++ // OR:
static const CORBA::Long MAX_NAMES = 20; // Standard C++ };
138
IT-SC book: Advanced CORBA® Programming with C++
This mapping preserves the nesting of scopes used in the IDL, but it means that IDL constants that are nested inside interfaces are not C++ compile-time constants. In classic (non-standard) C++, initialization of static class members is illegal, so instead of generating the initial value into the header file, the IDL compiler generates an initialization statement into the stub file. Standard C++, on the other hand, permits initialization of constant class members in the class header for integral and enumeration types. Therefore, in a standard environment, you may find that constants defined inside an interface end up being initialized in the class header.
Normally, the point of initialization is irrelevant unless you use an IDL constant to dimension an array:
char |
* |
entry_array[MAX_ENTRIES]; |
// |
OK |
char |
* |
names_array[NameList::MAX_NAMES]; |
// |
May not compile |
You can easily get around this restriction by using dynamic allocation, which works no matter how your IDL compiler maps constants:
char |
* entry_array[MAX_ENTRIES]; |
// |
OK |
char |
** names_array = new char *[NameList::MAX_NAMES] ; // |
OK |
|
String constants are mapped as a constant pointer to constant data:
const |
string |
MSG1 |
= |
"Hello"; |
const |
wstring |
MSG2 |
= |
L"World"; |
This maps to the following:
//
// If IDL MSG1 and MSG2 are at global scope:
// |
MSG1 = "Hello"; |
const char * const |
|
const CORBA::wchar * const |
MSG2 = L"World"; |
//
// If IDL MSG1 and MSG2 are in an IDL interface "Messages":
// |
|
class Messages { |
|
public: |
MSG1; // "Hello" |
static const char * const |
|
static const CORBA::wchar * const |
MSG2; // L"World" |
}; |
|
Note that if IDL constants are declared inside a module (instead of an interface), their mapping depends on whether you are using a classic or a standard C++ compiler:
module MyConstants {
const string GREETING = "Hello"; const double PI = 3.14;
139
