
- •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++
Chapter 5. IDL for a Climate Control System
5.1 Chapter Overview
Throughout the remainder of this book, we use a simple climate control system as a case study. The initial implementation of this system has a number of limitations. As we discuss new features, we progressively improve the implementation until we end up with a full-featured and realistic application.
Section 5.2 describes the functionality provided by the climate control system, Section 5.3 incrementally develops the interfaces to the system in IDL, and Section 5.4 contains the complete IDL specification for the system.
5.2 The Climate Control System
The climate control system controls the air-conditioning for various rooms in a large building. In addition, the same system controls the temperature of a number of manufacturing devices, such as freezers and annealing ovens. The system contains two kinds of devices: thermometers and thermostats. These devices are installed at various locations and support a proprietary instrument control protocol.
Thermometers report the current temperature at a location, whereas thermostats also permit a desired temperature to be selected. The climate control system attempts to keep the actual temperature as close as possible to this selected temperature. We assume that the system contains hundreds of thermometers and thermostats.
The entire collection of thermometers and thermostats can be controlled from a single remote monitoring station. An operator can monitor and set the desired temperature for each location, find specific devices via various search criteria, and raise or lower the temperature for a number of rooms as a group.
A climate control system server acts as a gateway between the proprietary instrument control network and CORBA applications. We use CORBA to manage the system because it allows us to use the regular corporate computing infrastructure instead of having to extend the proprietary network to all clients. In addition, APIs for the proprietary protocol may not be available for all the combinations of operating system and platform we want to use for clients. By using CORBA, we permit a much wider variety of client implementations, including client implementations in languages for which the proprietary API is not available.
5.2.1 Thermometers
A thermometer is a reporting device. Its purpose is to allow the monitoring station to inquire about the current temperature at the thermometer's location. Thermometers come equipped with a small amount of memory that holds additional information.
122

IT-SC book: Advanced CORBA® Programming with C++
Asset number
Each thermometer has an asset number. This number is unique and is assigned when the thermometer is manufactured (for example, written into EPROM). The asset number therefore cannot change during the lifetime of a thermometer. The asset number also acts as the unique proprietary network address for each device; the proprietary API requires an asset number for remote access to a device.
Model
Thermometers come in different models. The model determines aspects such as the precision and range of the device. The model identification is stored in read-only memory and can be read remotely.
Location
Each thermometer stores a short string identifying its current location, such as "Room 414." This string is held in writable memory, so it can be updated. This may be necessary when a thermometer is physically moved to a different location or if the name of a room is changed.
5.2.2 Thermostats
Thermostats offer all the functionality of thermometers—that is, thermostats can report the current temperature, and they have an asset number, model, and location. The asset numbers of thermostats and thermometers share a namespace. This means that if a particular thermostat has asset number 5, no other thermostat or thermometer can have asset number 5.
Thermostats come equipped with a dial for setting the desired temperature. It is possible to remotely read as well as change the setting of the dial.
Each thermostat imposes limits on the range of temperatures that can be selected and does not permit a setting outside the legal range. Different thermostats have different legal temperature ranges, depending on the model. Different models are required for different environments, such as offices, freezers, and semiconductor annealing ovens.
5.2.3 The Monitoring Station
The monitoring station (known as a controller) permits access to and control of the devices in the system. An operator can list all devices in the system, locate specific devices by various search criteria, and make relative changes to the temperature setting of a group of thermostats.
Listing Devices
A list operation returns a list of all devices connected to the system.
Relative Temperature Changes
123

IT-SC book: Advanced CORBA® Programming with C++
A change operation accepts a list of thermostats together with a relative temperature setting (a delta value). The operation adjusts the nominal temperature setting of each thermostat on the list up or down by the requested amount.
Some thermostats may not be able to make the required adjustment. For example, one of the thermostats on the list may already be at its maximum setting and unable to increase the nominal temperature any further. For changes that exceed the permissible range of one or more thermostats, the operation behaves as follows.
For thermostats that can accept the requested change, the new setting is established.
For thermostats that cannot accept the requested change, the original temperature remains unchanged. In addition, an error report shows the details of what went wrong for each thermostat.
Finding Devices
This operation permits an operator to locate specific devices by their asset number, location string, or model number.
5.3 IDL for the Climate Control System
Please note that the IDL for the climate control system was designed mainly as an educational exercise. We sacrificed elegance in order to use a representative subset of the language while keeping the example to manageable size. This also meant ignoring some of our own advice; for example, we have used attributes when operations would be more appropriate. Keep in mind that there are hundreds of ways to write the IDL for this application, many of which are better than the one we use here.
The problem description for the climate control system suggests the object model shown in Figure 5.1. (The diagram omits the implied inheritance of every IDL interface from Object.) Because a thermostat offers all the functionality of a thermometer, it can be considered a special kind of thermometer. We use inheritance to express this.
Figure 5.1 UML Object model for the climate control system.
Each thermometer—and, by inheritance, each thermostat—has a mandatory association with exactly one controller. A controller manages any number of devices (possibly none). As indicated by the association arrow, we can navigate the association from the controller
124

IT-SC book: Advanced CORBA® Programming with C++
to a device but cannot navigate the association in the opposite direction. Given a device, it is not possible to find its managing controller.
5.3.1 IDL for Thermometers
From the problem description, we can easily model a thermometer as follows:
typedef unsigned long |
AssetType; |
typedef string |
ModelType; |
typedef short |
TempType; |
typedef string |
LocType; |
interface Thermometer { |
model; |
readonly attribute ModelType |
|
readonly attribute AssetType |
asset_num; |
readonly attribute TempType |
temperature; |
attribute LocType |
location; |
}; |
|
The model, asset number, location, and current temperature can all be provided as IDL attributes. The location of the thermometer is the only modifiable attribute. The remaining attributes are declared read-only.
5.3.2 IDL for Thermostats
The IDL for thermostat devices simply adds to the basic functionality provided by thermometers:
interface Thermostat : Thermometer {
struct BtData { |
requested; |
TempType |
|
TempType |
min_permitted; |
TempType |
max_permitted; |
string |
error_msg; |
};
exception BadTemp { BtData details; }; TempType get_nominal();
TempType set_nominal(in TempType new_temp) raises(BadTemp);
};
Instead of using attributes, a thermostat provides an accessor (get_nominal) and a modifier operation (set_nominal). set_nominal returns the previously set temperature if it succeeds. If it fails, it raises a BadTemp exception. The return value is undefined in the presence of an exception.
Note that the BadTemp exception has only a single data member, which in turn is a structure. This may seem strange. After all, we could have written this as follows:
exception BadTemp { TempType requested;
TempType min_permitted;
125

IT-SC book: Advanced CORBA® Programming with C++
TempType max_permitted; string error_msg;
};
The reason for placing the details in a separate structure is that exceptions are not permissible as a data type. As you will see in a moment, by using a structure, you can reuse the exception details from a set_nominal operation for the change operation on the controller.
5.3.3 IDL for the Controller
The list operation can be implemented by returning a polymorphic list of devices:
interface Controller {
typedef sequence<Thermometer> ThermometerSeq; ThermometerSeq list();
// ...
};
The list operation simply returns a sequence of Thermometer references. Because thermostats are thermometers, the sequence can contain a mixture of thermometers and thermostats. Clearly, this implies that the receiver must somehow be able to work out whether a particular object reference in the sequence belongs to a thermostat or denotes only a thermometer. As you will see in Section 7.6.4, this is possible (CORBA provides a mechanism similar to a C++ dynamic cast for object references).
The change operation implements a bulk update of a number of thermostats:
interface Controller { // ...
typedef sequence<Thermostat> ThermostatSeq; struct ErrorDetails {
Thermostat tmstat_ref; Thermostat::BtData info;
};
typedef sequence<ErrorDetails> ErrSeq; exception EChange {
ErrSeq errors;
};
void change(in ThermostatSeq tlist, in short delta) raises(EChange);
// ...
};
Note that change expects a sequence of Thermostat references. Only thermostats (but not thermometers) permit a nominal temperature to be set. A thermometer is not a thermostat, and therefore a thermometer cannot appear in a sequence of thermostats. This makes the definition of change type-safe; there is no way to accidentally get a
126

IT-SC book: Advanced CORBA® Programming with C++
thermometer into the input sequence (at least with the C++ mapping, which is statically type-safe.)
If one or more of the thermostats cannot make the requested change, an EChange exception is raised. The exception contains the single data member errors, which is a sequence of error reports. Each error report in turn contains the object reference of the thermostat that encountered the problem (in the member tmstat_ref) together with the details of the exception raised by that thermostat (in the member info).
The find operation permits searching for devices by asset number, location, or model number. An enumerated type indicates the type of search, and the search key is supplied as a union:
interface Controller { // ...
enum SearchCriterion { ASSET, LOCATION, MODEL }; union KeyType switch(SearchCriterion) {
case ASSET:
AssetType asset_num; case LOCATION:
LocType loc; case MODEL:
ModelType model_desc;
}; // ...
};
The find operation expects a sequence of pairs of search key and object references:
interface Controller { // ...
struct SearchType { KeyType key; Thermometer device;
};
typedef sequence<SearchType> SearchSeq; void find(inout SearchSeq slist);
// ...
};
For instructional purposes, we have made the definition of this operation unnecessarily complicated. A more realistic approach would split find into three separate operations (one for each type of search) and would return the matching object references as the return value (instead of using an inout parameter).
To locate one or more devices, the caller supplies a sequence of type SearchSeq. The sequence contains one element for each search key. This permits the caller to search for devices by several search criteria in a single call. For example, to locate all devices in
127

IT-SC book: Advanced CORBA® Programming with C++
Room 414 or with the asset number 123, the caller creates a sequence with two elements, one for each search criterion.
The find operation looks for the devices nominated by the search keys. If a matching device is found, it overwrites the device member in the SearchType structure with the object reference of the matching device. If no matching device is found, the device member is set to the nil reference to indicate a failed search for this key to the caller. The initial value of the device member (as sent by the client) is ignored.
Figure 5.2 shows an example in which the client supplies two search records. One record looks for devices in Room 414, and the other record looks for the device with asset number 123. Assume that no devices are in Room 414 but that a device with asset number 123 actually exists. The corresponding search sequence is shown before and after the call.
Figure 5.2 Search sequence before and after a call.
Some search keys can result in more than one matching device. For example, we may have two model Sens-A-Temp thermometers in the system. In this case, the find operation increases the length of the inout sequence to return the matching devices, as shown in Figure 5.3.
Figure 5.3 Growing a search sequence.
128