- •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++
The relationship between the bottom consumer and the middle supplier represents the canonical push model.
The relationship between the bottom consumer and the bottom supplier represents the hybrid pull/push model.
Thus, Figure 20.7 shows that an event channel is capable of fulfilling all four roles simultaneously.
Although the event channel is fulfilling multiple roles, each consumer receives all events provided by all suppliers. The event channel decouples the consumers and suppliers so that none of them knows whether the other consumers and suppliers are connected for pushing or for pulling.
20.5 Event Service Interfaces
The CosEventComym module provides the IDL definitions needed to interact with event channels. Many of these interfaces, however, are concerned only with suppliers and consumers; they make no mention of event channels. As Figure 20.8 shows, the event channel is itself both a supplier and consumer.
Figure 20.8 Event channel proxy supplier and proxy consumer interfaces.
These supplier and consumer interfaces are called proxy interfaces because they represent the actual supplier and the actual consumer to each other. In other words, these interfaces provide the illusion to consumers and suppliers that they are interacting with the actual suppliers and actual consumers, respectively.
20.5.1 Interfaces for the Push Model
Following are the interfaces that support the push model.
module CosEventComm
exception Disconnected {};
interface PushConsumer {
void push(in any data) raises(Disconnected);
void disconnect_push_consumer();
};
interface PushSupplier {
void disconnect_push_supplier();
}; // ...
};
803
IT-SC book: Advanced CORBA® Programming with C++
A push consumer implements the PushConsumer interface and registers an object reference for it with a supplier. A supplier then uses that object reference to send event data to the PushConsumer object by invoking its push operation.
Both consumers and suppliers can disconnect from each other. If an event supplier decides that it no longer wants to send events to a particular consumer, it can invoke the disconnect_push_consumer operation on that consumer. If a supplier invokes push on a disconnected consumer, the supplier gets a Disconnected exception.
Alternatively, if a push consumer no longer wants to receive events, it can disconnect from its supplier by invoking disconnect_push_supplier on the supplier's PushSupplier object. This implies that the supplier must have given a PushSupplier object reference to the consumer. This normally occurs at registration time, as described in Section 20.5.3.
Event data is sent in the form of an any, and that allows any IDL data type to be used to convey information about the event. This implies that the consumer either knows what type to expect in the any or is willing to determine the contents dynamically using the DynAny interface (see Chapter 17). Use of the any type also allows the event data to be passed unchanged through an event channel implementation. Without it, either the event channel IDL would have to specify the precise data type that all suppliers and consumers would have to use regardless of their problem domain, or the event channel would somehow have to support dynamic extensibility to allow suppliers and consumers to add type-specific event delivery operations as necessary. Using the any type is much more practical than either of these approaches.
20.5.2 Interfaces for the Pull Model
The interfaces that support the pull model, shown next, are essentially a mirror image of the interfaces for the push model.
module CosEventComm { interface PullSupplier {
any pull() raises(Disconnected);
any try_pull(out boolean has_event) raises(Disconnected);
void disconnect_pull_supplier();
};
interface PullConsumer {
void disconnect_pull_consumer();
}; // ...
};
804
IT-SC book: Advanced CORBA® Programming with C++
A consumer pulls events from a supplier in one of two ways.
The consumer invokes the pull operation to block until an event is available and can be returned.
The consumer invokes the try_pull operation to poll for events without blocking. If no events are available, try_pull returns immediately with its out parameter has_event set to false to indicate that no event data was available. If an event is available, try_pull returns the event data and sets the has_event parameter to true. If a consumer is no longer interested in pulling events from a supplier, it invokes the disconnect_pull_supplier operation. Any further invocation of pull or try_pull will raise the Disconnected exception to the invoking consumer. A supplier can indicate its desire to break the pull connection by invoking disconnect_pull_consumer on the consumer object's PullConsumer interface. As with the push model, this capability implies that the supplier and consumer have already exchanged PullSupplier and PullConsumer object references.
20.5.3 Event Channel Interfaces
So far, our descriptions of the interfaces used for pushing and pulling have not mentioned the event channel. As Figure 20.8 shows, this is because the event channel presents itself as a consumer to suppliers and as a supplier to consumers. However, event channels also provide administrative interfaces that allow consumers and suppliers to establish logical connections with it. The IDL types related to event channel administration are defined in the CosEventChannelAdmin module.
module CosEventChannelAdmin { interface ProxyPushSupplier; interface ProxyPullSupplier;
interface ProxyPushConsumer; interface ProxyPullConsumer;
interface ConsumerAdmin {
ProxyPushSupplier obtain_push_supplier(); ProxyPullSupplier obtain_pull_supplier();
};
interface SupplierAdmin {
ProxyPushConsumer obtain_push_consumer(); ProxyPullConsumer obtain_pull_consumer();
};
interface EventChannel {
ConsumerAdmin |
for_consumers(); |
SupplierAdmin |
for_suppliers(); |
void |
destroy(); |
}; |
|
// ... |
|
};
805
IT-SC book: Advanced CORBA® Programming with C++
The EventChannel interface supplies three operations.
Consumers that want to connect to an event channel invoke its for_consumers operation, which returns a ConsumerAdmin object reference.
Suppliers that want to connect to an event channel invoke its for_suppliers operation, which returns a SupplierAdmin object reference.
Invoking destroy on an event channel permanently destroys it, including any events that it has not yet delivered. Moreover, destroying the event channel also destroys all administrative objects created by that channel and all proxy objects created by those administrative objects. Any connected consumers and suppliers are notified when their channel is destroyed.
After invoking for_consumers on an event channel, the consumer must decide whether it wants to use the push model or the pull model. If it wants to be a push consumer, it invokes the obtain_push_supplier operation on the ConsumerAdmin object returned from for_consumers. Otherwise, it invokes obtain_pull_supplier. Similarly, suppliers must decide whether they want to support the push or pull model, so they can invoke the appropriate operation on the
SupplierAdmin returned from EventChannel::for_suppliers.
Establishing Push Model Connections
A consumer that wants to register as a push consumer first obtains a
ProxyPushSupplier object reference by invoking obtain_push_supplier on a ConsumerAdmin object. Similarly, a supplier that wants to push events first obtains a
ProxyPushConsumer by invoking SupplierAdmin::obtain_push_consumer. These proxy interfaces are shown next.
module CosEventChannelAdmin { exception AlreadyConnected {}; exception TypeError {};
interface ProxyPushSupplier : CosEventComm::PushSupplier { void connect_push_consumer(
in CosEventComm::PushConsumer push_consumer ) raises(AlreadyConnected, TypeError);
};
interface ProxyPushConsumer : CosEventComm::PushConsumer { void connect_push_supplier(
in CosEventComm::PushSupplier push_supplier ) raises(AlreadyConnected);
}; // ...
};
806
IT-SC book: Advanced CORBA® Programming with C++
The ProxyPushSupplier interface inherits the CosEventComm:: PushSupplier interface, and ProxyPushConsumer inherits
CosEventComm::PushConsumer. These base interfaces are described in Section
20.5.1. These derived interfaces supply operations that allow consumers and suppliers, respectively, to establish connections to an event channel. A push consumer invokes connect_push_consumer on a ProxyPushSupplier in order to establish a connection to its PushConsumer object. Similarly, a push supplier invokes connect_push_supplier on a ProxyPushConsumer in order to connect itself.
A consumer invoking connect_push_consumer passes an object reference for its PushConsumer object. By invoking push on this object reference, the supplier delivers events to the consumer. As described in Section 20.5.1, the supplier can also invoke the disconnect_push_consumer to disconnect the consumer from the channel.
A supplier calls connect_push_supplier to make itself known to the target proxy push consumer. If it is interested in having the proxy push consumer notify it when it is about to be disconnected, it can pass a non-nil PushSupplier object reference as an argument. Otherwise, it must pass a nil object reference, in which case it will not be notified if it is disconnected by the proxy push consumer.
Establishing Pull Model Connections
A supplier that wants to register as a pull supplier first obtains a
ProxyPullConsumer object reference by invoking obtain_pull_consumer on a SupplierAdmin object. Similarly, a consumer that wants to pull events first obtains a ProxyPullSupplier by invoking ConsumerAdmin::obtain_pull_supplier. These proxy interfaces are shown next.
module CosEventChannelAdmin {
interface ProxyPullConsumer : CosEventComm::PullConsumer { void connect_pull_supplier(
in CosEventComm::PullSupplier pull_supplier ) raises(AlreadyConnected, TypeError);
};
interface ProxyPullSupplier : CosEventComm::PullSupplier { void connect_pull_consumer(
in CosEventComm::PullConsumer pull_consumer ) raises(AlreadyConnected);
}; // ...
};
Like their push counterparts described in the preceding section, these interfaces inherit the basic pull model interfaces defined in the CosEventComm module (see Section
20.5.2). ProxyPullConsumer and ProxyPullSupplier provide operations that
807
IT-SC book: Advanced CORBA® Programming with C++
allow pull suppliers and pull consumers, respectively, to establish connections to an event channel.
A supplier invoking connect_pull_supplier passes an object reference for its PullSupplier object. By invoking pull on this object reference, the consumer can retrieve events from the supplier. As described in Section 20.5.2, the consumer can also invoke the disconnect_pull_supplier to disconnect the supplier from the channel.
A consumer calls connect_pull_consumer to make itself known to the target proxy pull supplier. If it is interested in having the proxy pull supplier notify it when it is about to be disconnected, it can pass a non-nil PullConsumer object reference as an argument. Otherwise, it must pass a nil object reference, in which case it will not be notified if it is disconnected by the proxy pull supplier.
Connection Exceptions
A proxy supplier can be connected only to a single consumer; similarly, a proxy consumer can be connected only to a single supplier. To enforce this, all connection operations that the proxy interfaces provide can raise the AlreadyConnected exception. This exception is raised if a connection operation is invoked multiple times on the same proxy. For example, the following code will cause an AlreadyConnected exception to be raised.
proxy_push_supplier->connect_push_consumer(a_push_consumer); proxy_push_supplier->connect_push_consumer(another_push_consumer);
The second invocation of connect_push_consumer will raise the AlreadyConnected exception because the first invocation established a connection to the target proxy supplier.
The ProxyPushSupplier::connect_push_consumer and the ProxyPullConsumer::connect_pull_supplier can also raise the
TypeError exception. This exception is raised if the proxy supplier and proxy consumer objects of an event channel implementation impose additional type constraints on the consumers and suppliers that are connected to them. This exception is present primarily to support typed event channels, which are event channels that pass specific event data types rather than pass event data using the IDL any type. Because implementations of typed event channels are rare, there is little real-world experience with using them, so we do not cover them in this book.
Disconnection
Invoking disconnection operations on proxy supplier and consumer objects effectively destroys them. This is because the disconnection operations provide the only means by which an event channel knows it can clean up connections that are no longer needed. It
808
IT-SC book: Advanced CORBA® Programming with C++
might have been better if the designers of the OMG Event Service had made the names of the disconnection operations on the proxy supplier and consumer interfaces reflect their destructive side effects. However, this was not possible because the disconnection operations are inherited from the base consumer and supplier interfaces provided in the CosEventComm module. Because your user applications implement these base interfaces in order to send and receive events, you can make their disconnection operations perform whatever actions you deem necessary, including destroying the target object.
Although the Event Service specification does not require it, you should always explicitly invoke disconnection operations when you no longer want to supply or receive events. Otherwise, your event channel might have a difficult time determining whether and when it can clean up its proxy consumer and supplier objects. Over time, these stranded proxy objects can bloat an event channel process and affect its event delivery performance.
20.5.4 Event Channel Federation
Because event channels support the basic consumer and supplier interfaces for both push and pull, one event channel can be hooked to another event channel just as any other supplier or consumer can be. Figure 20.9 shows one event channel registered as a
PushConsumer of another.
Figure 20.9 Federated event channels.
Coupling event channels in this manner allows you to distribute the responsibility and costs of event delivery. In Figure 20.9 the consumer event channel has four consumers of its own, and the supplier event channel has two consumers. If the consumer event channel were not registered as a consumer of the supplier event channel, all four of its
809
