
- •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++
close its connection, the client would conclude that the server had crashed and would raise an exception in the client application code.[5]
[5] In GIOP 1.2, a CloseConnection message can also be sent from client to server.
MessageError
This message is sent in response to any GIOP message that is malformed in some way. For example, MessageError is returned if a GIOP message contains the wrong magic value (a string other than GIOP in the first four bytes) or if the GIOP version number is unknown to the receiver.
Fragment
If a GIOP 1.1 client decides to send messages in fragments, the first fragment is a Request message with the fragment flag set to true. The remainder of the request is sent by the client in Fragment messages. Each fragment contains more data for the request, together with a flag that indicates whether more fragments are to follow. While there are more fragments to follow, the flag is true. The final Fragment message in a series of fragments sets this flag to false to indicate that the server has received the last fragment and can now start processing the request.
13.5 GIOP Connection Management
The interaction model seen by CORBA clients and servers is connectionless; a client simply sends a request whenever it feels like it, and the request causes a virtual function to be called in the server. Neither client nor server application code ever opens or closes a connection. However, GIOP requests are dispatched over a connection-oriented transport, so the CORBA run-time environment must take care of managing connections on behalf of clients and servers.
The CORBA specification does not require any particular connection management strategy for ORBs. Instead, GIOP specifies just enough about connection management to enable interoperability among implementations, and it provides sufficient hooks in the protocol to allow an ORB vendor to choose between simple and sophisticated connection management strategies.
On the client side, an ORB has considerable choice as to how it manages connections from clients to servers. For example, a simple-minded (and unrealistic) ORB could simply open and close a separate connection for every request made by a client. This would be a prohibitively slow (but compliant) implementation. A typical problem for ORBs is what to do if a client exceeds the number of connections that the operating system is willing to allocate to it. Depending on the vendor, the ORB might simply raise an exception to the application code when it runs out of connections, whereas a more sophisticated ORB might multiplex requests onto fewer connections than the number of target servers by dynamically opening and closing connections as necessary.
541

IT-SC book: Advanced CORBA® Programming with C++
On the server side, a similar problem presents itself to the ORB. If there are more clients who want to communicate with a server than the number of available connections, the server-side run time may simply stop accepting connections. In that case, clients receive a TRANSIENT exception when the TCP/IP connection timer expires. A more sophisticated ORB would send CloseConnection messages to clients that do not have outstanding requests and thereby reclaim idle connections for use with other clients.[6]
[6] Note that the number of clients that can concurrently have a request in progress is limited by the number of connections available to the server. GIOP does not permit a server to close a connection while a request is outstanding on that connection.
The specification leaves a wide range of choices open to ORB implementers to avoid restricting the environments in which ORBs can be used. For example, if CORBA were to require a complicated strategy for reusing connections, it would penalize an ORB that runs in an environment where connections are available in large numbers (the ORB vendor would have to implement the strategy without any real benefit). Conversely, an ORB may need to run in an embedded environment where connections are at a premium. In that case, the vendor can implement a strategy that aggressively reuses connections at the cost of sacrificing some performance.
In practice, most general-purpose ORBs open a connection when a client first uses an object reference to an object in a particular server, and they close the connection when the reference count on the proxy for the target object drops to zero. If a client holds multiple references to objects in the same server, most ORBs multiplex requests to all objects in that server over the same single connection. This means that the client uses only as many connections as there are distinct server processes it communicates with. On the server side, many ORBs simply give up and stop accepting connection requests when the server reaches its connection limit. Other ORBs use the CloseConnection message to reclaim idle connections. If you are planning to use a large number of clients (more than 100 or so) with the same server simultaneously, you should ask your ORB vendor about the connection management strategy for the server side.
13.6 Detecting Disorderly Shutdown
In Section 13.4.3, we mention that a server sends a CloseConnection message if it wants to close a connection. This means that a client can always distinguish orderly connection shutdown from disorderly connection shutdown. If the client-side run time encounters a broken connection without having first received a CloseConnection message, it can conclude either that the server has crashed or that connectivity is lost. In either case, it raises a system exception to the client application code, possibly after attempting to rebind first.[7]
[7] At least, that is the theory. In practice, we have seen defective implementations of TCP/IP that do not reliably report disorderly connection closure on non-UNIX platforms.
However, the same is not true for the server. If a client decides that it is finished with a server (typically because the reference count on the last proxy to an object in the server
542

IT-SC book: Advanced CORBA® Programming with C++
drops to zero), the client simply closes the connection without first sending a message. This means that the server simply sees a closed connection. The server cannot distinguish orderly connection closure from disorderly closure. For example, if the client crashes, the server just sees a closed connection but does not know why the connection was closed. (With GIOP 1.2, sending a CloseConnection message to indicate orderly connection closure is mandatory for both client and server. This mitigates, but does not eliminate, the problems we discuss in the remainder of this section.)
This has important ramifications for garbage collection and the life cycle of objects. Frequently, a server offers a factory operation to clients. Clients can create new objects in the server by invoking an operation and can later destroy the objects by invoking another operation (typically, by calling destroy or CosLife-Cycle::remove). A problem arises if a client crashes after it has created an object and therefore never gets around to deleting the object again. There is no way for the server to know whether the client has gone away permanently or simply has closed the connection temporarily because it is short of connections. This means that the server must keep the object alive because the server cannot know whether the object is still of interest to the client.
Some ORBs offer an API call that allows a server to monitor the state of network connections. If a network connection closes, the ORB invokes a callback function in the server application code. This gives the server an opportunity to clean up objects it has created on behalf of a client. However, any such strategy is fraught with problems. For one thing, the server must somehow be able to associate the closed connection with a particular client in order to determine which objects it should destroy. Second, because there is no CloseConnection message in GIOP from client to server (except for GIOP 1.2), monitoring of network connections makes assumptions about the connection management used by the client. In effect, the server assumes that if a client closes a connection, it means that the server can clean up the objects created by that client. This is not a valid assumption. For example, if the client is written using a different vendor's ORB, it may use an aggressive connection reuse strategy. In that case, the client might deliberately close a connection, but the server would conclude that the client has crashed and mistakenly destroy the objects created by the client.
If you decide to use extensions provided by your ORB vendor to monitor connection closure, be aware that you are outside the guarantees provided by the GIOP specification. If you know that clients will be written using the same vendor's ORB, things will work fine. But keep in mind that using connection closure for garbage collection relies on proprietary extensions and may not work with clients using another ORB. We discuss other, more portable strategies for garbage collection in Chapter 12.
13.7 An Overview of IIOP
GIOP specifies most of the protocol details that are necessary for clients and servers to communicate. GIOP is independent of a particular transport and is therefore an abstract protocol, whereas IIOP is specific to TCP/IP and is therefore a concrete implementation (or mapping) of GIOP. To turn GIOP into a concrete protocol, IIOP merely needs to
543

IT-SC book: Advanced CORBA® Programming with C++
specify the encoding of IORs. Recall from Section 2.5.3 that an IOR consists of three main components: the repository ID, the endpoint information, and the object key. IIOP merely specifies how an IOR encodes the TCP/IP addressing information inside an IOR, so the client can establish a connection to the server to send a request.
Like GIOP, IIOP has been revised twice since its inception, so CORBA specifies IIOP 1.0, 1.1, and 1.2. IIOP 1.1 adds the notion of tagged components to an IOR. Tagged components are required to support some of the newer features of CORBA, such as support for different wide character codesets. IIOP 1.2 supports the bidirectional functionality of GIOP 1.2.
Any version of IIOP references can be carried over any version of GIOP. However, for bidirectional functionality to be available, IIOP 1.2 requires GIOP 1.2 or later.
The endpoint information inside an IOR that uses IIOP is encoded according to the following IDL:
module IIOP { |
// PIDL |
|
struct Version { |
|
|
octet |
major; |
|
octet |
minor; |
|
}; |
|
|
struct ProfileBody_1_1 { |
||
Version |
|
iiop_version; |
string |
|
host; |
unsigned short |
port; |
|
sequence<octet> |
object_key; |
sequence<IOP::TaggedComponent> components; };
};
We show the version 1.1 and 1.2 definition here (the 1.0 definition is identical except that it does not use tagged components). A structure of type ProfileBody_1_1 completely identifies the target object of a request: both the host and port at which the server can be found and the object in that server the request is for.
The iiop_version field indicates the major and minor revision of the protocol.
The host and port fields specify the host and port number at which the server listens for requests. The host can be encoded either in dotted-decimal notation (such as 234.234.234.234) or as a host name (such as acme.com).
The object_key field is a sequence of octets that identifies the particular target object. The components field contains a sequence of tagged components (for IIOP 1.1 only). Each tagged component is a structure containing two fields. The first field identifies the type of component, and the second one contains the data for that component (see page 628).
544