- •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++
interface Thermometer {
typedef string<16> ModelType;
};
interface Hygrometer {
typedef string<32> ModelType;
};
interface HygroTherm : Thermometer, Hygrometer { attribute ModelType model; // Error, 16 or 32 chars?
};
This is illegal because it is no longer clear whether HygroTherm::ModelType has 16 or 32 characters. You can easily get around this problem by using a qualified name:
interface Thermometer {
typedef string<16> ModelType;
};
interface Hygrometer {
typedef string<32> ModelType;
};
interface HygroTherm : Thermometer, Hygrometer {
attribute Thermometer::ModelType model; |
// Fine, 16 chars |
}; |
|
4.18 Names and Scoping
IDL's rules for names and name scope resolution are similar to those used by C++ but add a few restrictions to avoid awkward constructs in a number of language mappings. We present these rules here mainly for completeness. If you write clean IDL that uses different identifiers for different things, you will never be in doubt as to which particular definition of an identifier is in scope.
4.18.1 Naming Scopes
Each of the following IDL constructs establishes its own naming scope: Modules
Interfaces
Structures Unions Exceptions
Operation definitions
Identifiers need be unique only within their own scope, so the following IDL is legal:
module CCS { |
TempType; |
|
typedef short |
// MAX_TEMP is a short |
|
const TempType |
MAX_TEMP = 99; |
|
interface Thermostat { |
// OK |
|
typedef long |
TempType; |
|
TempType |
temperature(); |
// Returns long |
CCS::TempType nominal_temp(); |
// Returns short |
|
110
IT-SC book: Advanced CORBA® Programming with C++
};
};
Even though it is legal, you should obviously avoid such reuse of identifiers because it is highly confusing.
4.18.2 Case Sensitivity
Within a naming scope, identifiers must be consistently capitalized:
module CCS { |
TempType; |
|
typedef short |
// Error |
|
const temptype |
MAX_TEMP = 99; |
|
}; |
|
|
The preceding specification does not compile because after an identifier is introduced into a scope, the identifier must be capitalized consistently. Identifiers that differ only in case within the same scope are illegal:
module CCS { |
TempType; |
|
typedef short |
// Error |
|
typedef double |
temptype; |
|
}; |
|
|
After TempType is introduced into a scope, all other capitalizations are "used up." Within different naming scopes, different capitalizations are legal (but confusing):
module CCS { |
|
|
typedef short TempType; |
|
|
interface Thermometer { |
// OK |
|
typedef long |
temptype; |
|
temptype |
temperature(); |
// Returns long |
CCS::TempType |
nominal_temp(); |
// Returns short |
TempType |
max_temp(); |
// Error |
}; |
|
|
}; |
|
|
The definition of max_temp does not compile because the name resolution rules ignore the case of an identifier during name lookup. The TempType return type of max_temp first resolves to Thermometer::temptype and then generates an error because the compiler detects that TempType and temptype are used within the same scope.
On the other hand, the definition of nominal_temp compiles OK because the return type CCS::TempType uses a qualified name, and the capitalization of the qualified name agrees with the capitalization at the point of definition.
111
IT-SC book: Advanced CORBA® Programming with C++
4.18.3 Names in Nested Scopes
A name in a nested scope cannot be the same as a name in its immediately enclosing scope. For example:
module CCS { // ...
module CCS { // Error // ...
};
};
Similarly, an interface cannot define a name that is the same as the name of the interface:
interface SomeName {
typedef long SomeName; // Error
};
4.18.4 Name Lookup Rules
The IDL compiler resolves names by successively searching enclosing scopes. For example:
module CCS |
{ |
|
typedef short TempType; |
|
|
// ... |
|
|
module Sensors { |
// Ugly, but legal |
|
typedef long TempType; |
||
interface Thermometer { |
// Returns a long |
|
}; |
TempType temperature(); |
|
|
|
|
};
module Controllers { // ...
module TemperatureControllers { interface Thermostat {
TempType get_nominal_temp(); // Returns a short
};
};
};
};
In this example, the temperature operation returns a long value because as the compiler searches through the enclosing scopes, the closest definition of the name TempType appears inside module Sensors. The definition of CCS::TempType is hidden inside interface Thermometer by Sensors::TempType.
112
IT-SC book: Advanced CORBA® Programming with C++
On the other hand, the get_nominal_temp operation returns a short value because searching outward through its enclosing scopes, the compiler finds the CCS::TempType definition.
In the presence of inheritance, the compiler searches base interfaces first and then searches the enclosing scopes from the point of lookup. The enclosing scope of base interfaces is never searched during name lookup:
module Sensors { |
TempType; |
|
typedef short |
|
|
typedef string |
AssetType; |
|
interface Thermometer { |
|
|
typedef long TempType; |
// Returns a long |
|
TempType |
temperature(); |
|
AssetType |
asset_num(); |
// Returns a string |
}; |
|
|
}; |
|
|
module Controllers { |
TempType; |
|
typedef double |
|
|
interface Thermostat : Sensors::Thermometer { |
||
TempType |
nominal_temp(); |
// Returns a long |
AssetType |
my_asset_num(); |
// Error |
}; |
|
|
}; |
|
|
In this example, nominal_temp returns a long instead of a double because base interfaces are searched before the enclosing scope. In other words, inside interface
Thermostat, Sensors::Thermometer::TempType hides Controllers::TempType.
The definition of my_asset_num fails because AssetType is not defined at this point. Even though interface Thermometer is a base interface and uses AssetType, interface Thermometer does not define AssetType. When the compiler looks at the definition of my_asset_num, it does not consider Sensors::AssetType because the enclosing scope of base interfaces is never searched.
4.19 Repository Identifiers and pragma Directives
CORBA provides an Interface Repository that allows run-time access to IDL definitions. The IDL compiler assigns a repository ID to every type in a specification. This repository ID provides a unique identifier for each IDL type and is used as a key into the Interface Repository, where the corresponding type definition is stored.
Repository identifiers can have one of three possible formats, indicated by their ID field: IDL format (default):
•
• IDL:acme.com/CCS/TempType:1.0
•
113
IT-SC book: Advanced CORBA® Programming with C++
DCE UUID format:
•
• DCE:700dc518-0110-11ce-ac8f-0800090b5d3e:1
•
LOCAL format:
•
• LOCAL:my personal favorite type name identifier
•
By default, the IDL compiler generates repository IDs in IDL format.
The DCE format permits DCE universally unique identifiers (UUIDs) [29] to be used as repository identifiers. This is useful, for example, for CORBA-to-DCE protocol translation. The final digit following the colon is a minor version number.
The LOCAL format is completely unconstrained and permits any sequence of characters following the LOCAL: prefix. This format is useful for local interface repositories that do not need to conform to any convention. For example, you could use the LOCAL format to add repository identifiers that link into your revision control system.
4.19.1 The IDL Repository ID Format
The following specification illustrates how the default repository identifiers (in IDL format) are generated:
module CCS {
typedef short TempType; interface Thermometer {
readonly attribute TempType temperature;
};
interface Thermostat : Thermometer {
void |
set_nominal_temp(in TempType t); |
}; |
|
}; |
|
The generated repository identifiers for this specification are as follows:
IDL:CCS:1.0
IDL:CCS/Temptype:1.0
IDL:CCS/Thermometer:1.0
IDL:CCS/Thermometer/temperature:1.0
IDL:CCS/Thermostat:1.0
IDL:CCS/Thermostat/set_nominal_temp:1.0
As you can see, an IDL format repository ID consists of three parts (the IDL prefix, a scoped type name, and a version number). The scoped type name is formed by traversing
114
IT-SC book: Advanced CORBA® Programming with C++
the IDL definition from the outermost to the innermost scope, concatenating the identifiers for each scope with a slash.
4.19.2 The prefix Pragma
IDL repository identifiers provide unique names for every IDL type. However, the mechanism is not perfect; there is always the niggling question, "What if someone else also has created a module called CCS?" Of course, you can make a name clash highly unlikely by choosing a longer name. For example, if you work at the famous Acme Corporation, you could call the module Acme_Corporation_CCS. However, this is not pretty, and it generates very long identifier names for some language mappings. Alternatively, you could nest the CCS module inside another module called Acme_Corporation. This technique works, but it means that all the company's IDL definitions end up in a single module, and that creates administrative problems.
The IDL prefix pragma alleviates the problem by permitting you to add a unique prefix to a repository ID:
#pragma prefix "acme.com" module CCS {
// ...
};
This definition prepends the prefix acme.com to every repository ID:
IDL:acme.com/CCS:1.0
IDL:acme.com/CCS/Temptype:1.0
IDL:acme.com/CCS/Thermometer:1.0
IDL:acme.com/CCS/Thermometer/temperature:1.0
IDL:acme.com/CCS/Thermostat:1.0
IDL:acme.com/CCS/Thermostat/set_nominal_temp:1.0
The obvious question is, how does this help? After all, by adding another prefix at the front, we have simply pushed the problem further away and not solved it. The answer is twofold.
By using a distinct prefix, such as a trademark or a registered Internet domain name, you can make a name clash extremely unlikely.
The prefix for repository identifiers does not affect the generated code. Even though every repository ID has the acme.com prefix, the API generated from the IDL still looks exactly as if no prefix had been specified. Thus, you avoid ending up with ugly identifiers such as Acme_Corporation_CCS::Thermometer in the generated code.
A prefix pragma stays in effect either until it is changed explicitly or until the scope containing the pragma closes (at which point the previous prefix takes effect again). Note
115
IT-SC book: Advanced CORBA® Programming with C++
that an IDL source file is a scope for the purposes of #pragma prefix processing. This means that if you include a file in an IDL definition, any prefix in the included file does not affect the definitions following the #include directive.
It is a good idea to establish a unique prefix for your projects and to use it consistently. This practice ensures that other developers will not clash with your IDL (possibly months or years after it is deployed).
All specifications published by the OMG carry the prefix omg.org.
4.19.3 The version Pragma
IDL also supports a version pragma. It applies only to repository IDs in IDL format. For example:
#pragma prefix "acme.com" module CCS {
typedef short TempType; #pragma version TempType 1.8
// ...
};
This definition assigns version 1.8 to the repository ID for TempType, so the repository ID becomes IDL:acme.com/CCS/TempType:1.8.
The version identifier is a historical relic and is ignored by the ORB. You should never have any reason to change it from the 1.0 default. The version ID was added to repository IDs to allow an interface versioning mechanism to be added to CORBA in the future. As of this writing, no such versioning mechanism exists, and there are no moves in the OMG to add one. This means that versioning in CORBA is limited to specialization—you can treat a derived interface as a later version of a base interface.
Versioning by specialization works fine, provided that you do not have to change any of the base interface's type definitions. In addition, versioning by specialization requires that the semantics of operations in the base interface must not be changed if they are implemented in the derived interface. In practice, versioning is frequently used to address defects in a base interface instead of only to extend the base interface's functionality. Unfortunately, versioning by specialization is not suitable in this case. If types in the base interface must be changed or if the semantics of a base interface's operation must be changed, you have no choice except to define a new, unrelated interface.
4.19.4 Controlling Repository ID Formats with the ID Pragma
The ID pragma allows you to specify explicitly the format of the repository identifier for a type. The pragma applies to all three formats. Its use is best shown by example:
#pragma prefix "acme.com"
116
