
- •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++
ObjectId-to-servant association in its Active Object Map, just as it always does if it has the RETAIN policy. If no association is found but the application has registered a ServantActivator, the POA invokes it in an attempt to obtain a suitable servant. In other words, after an object has been deactivated, the POA acts the same as if it had never been activated in the first place. Alternatively, if a request arrives or if the application attempts explicit activation while etherealize is still running, reactivation will be blocked until the ServantActivator has finished etherealizing the servant. After that, reactivation will occur as usual.
Because deactivate_object does not remove the object's entry from the Active Object Map until there are no more active requests for that object, a steady stream of incoming requests can actually keep the object from being deactivated. This is a side effect of allowing the servant to finish its normal processing before deactivation occurs. A servant performing such processing may invoke recursive method calls on the object it incarnates, and deactivation should not necessarily prevent those method invocations. Also, if a servant already has a method in progress when the application calls deactivate_object and if that method is blocked waiting for another long-running operation to complete, actual deactivation will be blocked until the method in progress finishes. You must be aware of these types of situations and be sure that your applications do not prematurely delete their servants out from under methods that are still in progress. As we recommend in Section 11.7.5, the best way to clean up your servants with a RETAIN POA is to use a ServantActivator.
The deactivate_object operation is an important part of the process of destroying a CORBA object. After an application deactivates an object, new requests for that object either cause reactivation or result in the CORBA::OBJECT_NOT_EXIST exception. After your application either raises the OBJECT_NOT_EXIST exception directly for a given object or fails to register a servant so that the POA raises it, you must be careful never to reincarnate the object. OBJECT_NOT_EXIST is essentially an object death certificate—it is intended as a definitive statement that the object is gone for good. Remember, because the POA has no persistent state, it is the application, and not the POA, that ultimately decides whether a given object still exists. If you raise OBJECT_NOT_EXIST for a given object and then later bring it back to life, you will not only break the CORBA object model but also cause confusion for your client applications and your administrative tools.
We discuss deactivate_object and object destruction issues further in Chapter 12 when we cover the OMG Life Cycle Service [21].
11.10 Request Flow Control
Our descriptions of servants and servant managers have shown how the POA provides applications with a great degree of flexibility in managing their own resources. For example, servant managers and default servants enable tight control over the amount of
440

IT-SC book: Advanced CORBA® Programming with C++
memory devoted to servant storage, allowing applications with many objects to scale gracefully.
Another aspect of resource management relates to the rate of requests that a server application can handle. As shown in Figure 9.1, each POA has an associated POAManager that essentially acts as a faucet or valve that allows you to control the flow of requests into the POA. Figure 11.9 illustrates the relationships among an application, an ORB, POAManager objects, and POAs.
Figure 11.9 Relationships among applications, ORBs, POAManagers, and POAs.
A single application may actually contain multiple ORB instances if it invokes CORBA::ORB_init multiple times with different arguments, but that is atypical and is therefore not shown here. In Figure 11.9, the application contains one ORB, and it in turn contains a single Root POA. The application has created a hierarchy of child POAs descending from the Root POA. It also has two POAManager objects: one for the Root POA and some of its descendants and the other for a different set of POAs descended from the Root POA. Although we do not show them, each POA typically also has one or more servants associated with it.
Applications use the POAManager interface to allow requests to pass into a POA unimpeded, to discard or hold requests, or to deactivate all request handling.
module PortableServer { interface POAManager {
exception AdapterInactive {};
441

IT-SC book: Advanced CORBA® Programming with C++
enum State { HOLDING, ACTIVE, DISCARDING, INACTIVE };
State |
get_state(); |
|
void |
activate() raises(AdapterInactive); |
|
void |
hold_requests(in boolean wait_for_completion) |
|
|
raises(AdapterInactive); |
|
void |
discard_requests(in boolean wait_for_completion) |
|
|
raises(AdapterInactive); |
|
void |
deactivate( |
etherealize_objects, |
|
in boolean |
|
|
in boolean |
wait_for_completion |
) raises(AdapterInactive);
};
// ...
};
The four operations provided by the POAManager interface (other than the get_state operation) correspond to the four possible states of a POAManager object. You invoke the activate operation to cause the target POAManager to transition into the active state and let requests flow through to the POA or POAs under its control.
You call the hold_requests operation to change the target POAManager into the holding state. In this state, the POAManager queues all incoming requests for the POA or POAs under its control. The maximum number of requests that a POAManager can queue while in the holding state is implementation-dependent. If the POAManager reaches its queuing limits, it may discard each request by raising the standard CORBA:: TRANSIENT system exception, indicating that the client should retry the request. If the wait_for_completion argument to hold_requests is false, the operation returns immediately after changing the state of the POAManager. If wait_for_completion is true, first the POAManager state is changed to holding, and then the operation does not return either until any requests that were already in progress complete or the state of the POAManager is changed from the holding state to some other state by another thread.
You invoke the discard_requests operation to cause the target POAManager to change to the discarding state. This state causes the POAManager to throw each incoming request away without queuing it and without delivering it to the target POA; instead, it raises the CORBA::TRANSIENT exception back to the client. If the wait_for_completion argument to discard_requests is false, the operation returns immediately after changing the state of the POAManager. If wait_for_completion is true, first the POAManager state is changed to discarding, and then the operation does not return until any requests that were already in progress
442

IT-SC book: Advanced CORBA® Programming with C++
complete or the state of the POAManager is changed from the discarding state to some other state by another thread.
You invoke the deactivate operation to change the state of the target POAManager to the inactive state. A POAManager in this state is no longer capable of processing requests and cannot be reactivated. If new requests arrive for objects in the POA or POAs controlled by the inactive POAManager, they are rejected in an implementation-specific manner. Some ORBs might raise the standard CORBA::OBJ_ADAPTER system exception back to the client, and others might transparently redirect the client ORB to another object. Unlike the holding or discarding states, raising CORBA::TRANSIENT back to the client is not a good approach because it implies that a retried request might reach the target object. As long as the POAManager is in the inactive state, retries will not succeed because all requests destined for that POAManager will be rejected. Raising CORBA::OBJECT_NOT_EXIST is also unacceptable because the target object may very well still exist. The ORB cannot know for sure whether the object still exists because it is inaccessible, even to the ORB, because of the inactive state of its
POAManager.
The get_state operation returns the POAManager's current state. Figure 11.10 shows a state diagram that illustrates the legal state transitions that a POAManager can make.
443

IT-SC book: Advanced CORBA® Programming with C++
Figure 11.10 POAManager state transition diagram.
A POAManager is associated with a POA at creation time. As shown in Section 11.5, the POA::create_POA operation has a reference to a POAManager object as its second argument.
If you pass a non-nil reference to a POAManager for this argument, the creation operation associates the new POA with that POAManager. This allows you to control request flow for multiple POAs via a single POAManager. On the other hand, if this argument is a nil reference, the implementation creates a new POAManager along with the new POA. Note that if a child POA has a separate POAManager from its parent POA, any state changes you apply to the POAManager of the parent POA do not affect that of the child and vice versa.
The state diagram in Figure 11.10 shows that newly created POAs begin their lives in the holding state. From the holding state they can legally transition to the active, discarding, or inactive states. You can transition a POA freely between the holding, discarding, and active states. After the state of a POA has been changed to inactive, however, the only legal change of state is to destroy it by invoking POA::destroy. In any state, except the inactive state, you can transition back to the same state without error. The reason that the inactive state is not a temporary state like the others is that ORB implementations may use it to perform resource cleanup such as closing network
444