- •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++
)
{
CORBA::Boolean has_event;
CORBA::Any_var any = supplier->try_pull(has_event); if (has_event) {
CCS::TStatEvent * event_data; if (any >>= event_data) {
//Use values from the event data
//struct here (not shown).
}
}
}
The check_for_thermostat_event function takes a PullSupplier_ptr as an argument, so we pass our ProxyPullSupplier to it. Because ProxyPullSupplier is derived from PullSupplier, automatic widening occurs when we pass the supplier variable to check_for_thermostat_event. To avoid blocking our GUI event loop and preventing windowing updates, check_for_thermostat_event always performs a try_pull on the supplier. Unlike the pull method, try_pull will not block waiting for an event if none is available. After invoking try_pull, we check the value of the has_event Boolean out argument to see whether an event was actually returned. If this argument is true, we then attempt to extract a pointer to a CCS::TStatEvent struct from the returned CORBA::Any. If this succeeds, our code can access the event data via the extracted structure pointer. Otherwise, the event data is not of the type we expect, and we ignore it.
20.7 Choosing an Event Model
In Section 20.4 we define the following four event delivery models: canonical push model
canonical pull model hybrid push/pull model hybrid pull/push model
When you develop an application that uses the Event Service, you must choose the model that is most appropriate for it. Your choice is affected not only by the characteristics of these models but also by the nature of your application and by issues related to event channel implementation.
20.7.1 Event Channel Implementation
Ultimately, much of the robustness and performance of an event-based system depends on the implementation of the event channel. The OMG Event Service Specification does not define requirements for key event channel characteristics, instead leaving design choices for each event channel implementation to those who create it. Although this approach makes the specification very flexible in terms of the environments it can support, it also means that the quality of service provided by event channels varies widely.
821
IT-SC book: Advanced CORBA® Programming with C++
One key characteristic of an event channel is throughput. If your application handles high rates of event delivery, you should evaluate your event channel implementation to determine how quickly it can deliver events. If we ignore the effects of multiple suppliers and consumers, the time required for an event channel to receive an event and push it out is mostly dependent on how efficiently the underlying ORB handles the IDL any type. Different ORBs use different techniques to marshal and unmarshal the any type, and some techniques are much more efficient than others. Some ORBs are highly tuned for any handling, but others do only an adequate job in this regard. We advise you to carefully measure the efficiency of your event channel before deploying a high-volume event-based production system on it.
The number of consumers and suppliers connected to an event channel can also influence its throughput. When an event arrives, the event channel must make that event available to each consumer that is connected. Delivery to each push consumer requires a separate CORBA request invocation from the event channel to the consumer; for pull consumers, the channel must buffer the event until the consumer requests it. Also, the more suppliers that are connected, the more events there are to receive and transmit to the consumers. Unless the event channel uses proprietary multicast protocols, which some of them do, there is simply no way around this limitation.
Although we speak of suppliers and consumers as being "connected" to the event channel, we do not mean to imply that these are necessarily network connections. Because operating systems impose limits on the number of open network connections a process can have, a quality event channel implementation must be able to handle more consumers and suppliers than it has network connections. For push suppliers and pull consumers, the event channel acts as a server, and this means that it can perform an orderly shutdown of one of these clients if it wants to reuse that connection for another supplier or consumer. Such a shutdown is transparent to the client ORB, which attempts to establish a new connection when it needs to push or pull a new event. For pull suppliers and push consumers, the event channel acts as a client, so in the extreme case it can open a network connection, send the request, and then immediately close the connection. Establishing and reestablishing connections in the ways described here can be costly, so be sure that the underlying operating system can support the necessary number of connections to your event channel.
Event channel implementations vary in what they store persistently. Most of them at least remember connection information so that consumer and supplier connections can be transparently restored if the event channel is stopped and restarted. Some implementations also persistently store event data that has not yet been pushed to or pulled from particular consumers. This is especially important for pull consumers that do not pull events very frequently.
Event channel implementations also must be able to deal with suppliers and consumers that are not well behaved. A pull supplier or push consumer that crashes should not cause the event channel to hang indefinitely waiting for a response. That would prevent other suppliers and consumers from getting their events handled in a timely manner. A quality
822
IT-SC book: Advanced CORBA® Programming with C++
event channel implementation allows characteristics, such as time-outs and the number of retries, to be configured through either a configuration subsystem, environment variables, or start-up options.
20.7.2 Push Model Considerations
Suppliers usually use the push model, primarily because it allows them to avoid the buffering needed when supporting the pull model. In some sense it is also the more natural and efficient of the two models. Suppliers usually want to notify all interested parties of an event as soon as it occurs, and the push model allows them to do that. Its efficiency arises from the fact that it avoids the overhead of polling.
A push supplier need not implement any CORBA objects unless it wants to be explicitly notified when disconnection occurs. This is ideal for applications that cannot support server functionality, perhaps for licensing, deployment, or security reasons. Unlike a push supplier, however, an application hosting a push consumer must be able to act as a server and receive events as they are generated.
20.7.3 Pull Model Considerations
Because this model relies entirely on polling for event delivery, it suffers from the problem of having to buffer events. For consumers that pull events infrequently, pull suppliers whose event buffers fill up must discard events. Choosing which events to discard depends entirely on the application. Some pull suppliers might want to discard the oldest events first, whereas others might stop accepting events after their buffers have filled. Still others might keep only the first one of several events that arrive within a certain timeframe, based on the likelihood that the second and subsequent events are duplicates of the first one.
Because this model relies on polling, excessive network traffic can be a problem if pull consumers poll for events frequently. To avoid polling, a pull consumer can invoke the blocking PullSupplier::pull operation rather than use the non-blocking try_pull. This approach reduces the amount of network traffic. However, for pull suppliers that are hosted by thread-per-request servers, it can result in the creation of a large number of threads in the server to handle these requests. Moreover, if the event data are not readily available in the pull supplier, each blocking pull request will require its thread to exist until the supplier has an event, using even more application resources. If the server uses a fixed-size thread pool, this situation could result in all available threads being blocked because of pull requests.
This model does not require pull consumers to act as servers, so it is suitable for use with pure clients that consume events.
20.8 Event Service Limitations
823
IT-SC book: Advanced CORBA® Programming with C++
Using an implementation of the Event Service can off-load the complicated task of reliable event delivery with multiple consumers and suppliers, but the OMG Event Service is not without limitations. Some of these limitations are explained in the following sections.
20.8.1 Multiple Suppliers
Because multiple suppliers can connect to an event channel, consumers may end up receiving far more events than they are interested in. This is because event channels deliver all events to all consumers; each consumer receives all events from all suppliers connected to the same event channel. Fortunately, type-safe extraction of event data from the IDL any type helps prevent consumers from acting on events that were not intended for them. However, it is a waste of resources for the event channel to send all events to all consumers only to have some of them discard the event data. The event channel may have to persistently store such events before they can be delivered and then use time and network connections in performing the deliveries. The network bandwidth required to transmit the events is also wasted.
You can alleviate this problem by setting up separate event channels for each type of event so that consumers that want to receive events from multiple sources can register with multiple event channels. Minimizing the number of event suppliers connected to each channel is also helpful, especially if there is only a single supplier per channel.
20.8.2 Lack of Reliability
When you design event-based applications, it is extremely important to keep in mind that event channels are fundamentally unreliable. Their lack of reliability stems from the difficulty of providing end-to-end guaranteed delivery in a service in which the channel has no way to throttle the supplier. If a supplier pushes so many events that the event channel cannot keep up with delivering all of them to its consumers, the event channel has no choice except to drop some of the events.
20.8.3 Lack of Filtering
Even if an event channel has only a single supplier connected to it, clients may still receive events in which they have no interest. This is because event channels pass events from their suppliers to their consumers without attempting to interpret event data in any way.
If an event channel could somehow filter events for each consumer, it could avoid the costs associated with sending unwanted events. Fortunately, the OMG has adopted the Notification Service [26], which supplies not only event filtering features but also structured event types and various degrees of control over the quality of service that an event channel provides. Furthermore, its interfaces inherit from the Event Service interfaces we describe in this chapter, allowing you to introduce a Notification Service
824
