
- •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 server must be running when a client sends a request. If the server is down, binding fails.
The inability to move servers from host to host is a major drawback in many deployment scenarios. For example, as an ORB installation evolves, it may be desirable to move a server from one machine to another simply to achieve a better distribution of processing load. If persistent references rely on direct binding, this optimization is impossible.
Direct binding requires servers to be running when clients want to use them, and there is no way to automatically start a server on demand when a request arrives. This requirement can be a problem, particularly in large installations that contain many servers. Even idle servers consume operating system resources such as swap space, network connections, page table entries, file descriptors, process table entries, and so on. For this reason, direct binding of persistent references is usually used only in special-purpose environments, such as embedded systems.
14.4 Indirect Binding via an Implementation Repository
Most general-purpose ORBs provide an implementation repository that supports indirect binding for persistent references. Indirect binding solves the problems associated with direct binding of persistent references, at the cost of slightly reduced performance for the first request from a client to an object. The implementation repository typically also provides automatic server start-up on demand and may provide different activation modes (see Section 14.6).
14.4.1 Standards Conformance of Implementation Repositories
The CORBA specification does not standardize the implementation repository and only suggests some functions that vendors may choose to implement. This lack of standardization is deliberate.
Implementation repositories are intimately related to their underlying platform. For example, implementation repositories must deal with details such as process creation and termination, threads, and signal handling. These functions vary widely among operating systems, so implementation repositories are inherently not portable.
The CORBA specification permits ORB implementations for environments ranging from embedded systems to global enterprise systems. It is not feasible to provide a specification that covers all possible environments because the exact functionality offered by an implementation repository varies dramatically for different environments.
Features such as object migration, scalability, performance, and load balancing all depend on the implementation repository. It therefore provides a major point at which ORB vendors can provide additional features and tailor repositories to target environments.
553

IT-SC book: Advanced CORBA® Programming with C++
Despite the lack of standardization, interoperability among ORBs from different vendors is still guaranteed. CORBA strictly specifies how an implementation repository interacts with clients during binding, so a client using vendor A's ORB can interoperate with an implementation repository from vendor B. Proprietary mechanisms exist only between servers and their respective implementation repositories. This means that a server written for vendor A's ORB requires an implementation repository from the same vendor. However, the interactions between servers and their repositories are not visible to clients and other servers and so do not compromise interoperability. Proprietary mechanisms between servers and their implementation repositories are confined to the ORB configuration, and the POA mapping ensures that server source code portability is preserved across ORBs from different vendors.
Because implementation repository features are vendor-dependent, the explanations that follow may not apply to all ORBs, and you will probably find that your particular ORB's repository differs somewhat from what we describe here. However, most general-purpose ORBs have implementation repositories that provide features along the lines we describe, so the explanations that follow should still be useful.
14.4.2 Implementation Repository Structure
An implementation repository has the following responsibilities.
It maintains a registry of known servers.
It records which server is currently running on which host and at which port number. It starts servers on demand if they are registered for automatic start-up.
Each implementation repository must run as a process that listens for requests on a fixed host and at a fixed port number. ORB vendors can reserve port numbers for their exclusive use through the Internet Assigned Numbers Authority (IANA). In addition, the implementation repository must run permanently. This means that implementation repositories are daemon processes that are usually started by a start-up script at boot time.
Table 14.1. Example population of an implementation repository's server table.
Logical Server Name |
POA Name |
Start-Up Command |
Host and Port |
CCS |
thermometer |
|
bobo.acme.com:1780 |
CCS |
thermostat |
|
bobo.acme.com:1780 |
CCS |
controller |
rsh bobo /opt/CCS/CCS_svr |
bobo.acme.com:1799 |
NameService |
ns_poa |
/opt/myorb/bin/name_svr -v |
|
Payroll |
PR_V1 |
|
fifi.acme.com:1253 |
Stock |
dept_1 |
|
|
Stock |
dept_2 |
|
|
An implementation repository maintains a data structure known as a server table to keep track of servers. Table 14.1 shows an example. For each server, the implementation repository records the following.
554

IT-SC book: Advanced CORBA® Programming with C++
Logical server name
The logical server name identifies what we think of as "the server." In other words, it identifies a process that implements one or more POAs when it is instantiated as a running process.
POA name
The POA name serves as a primary key into the table during binding. Whereas the logical server name serves mainly as an administrative handle to all the information about a server, the POA name occurs in object references and identifies at what address its server can be found.
The start-up command records how a server can be started on demand if it is not running at the time a client invokes a request. Note that a single logical server can use several POAs. If it does, there need not be a start-up command registered for every POA. For example, in Table 14.1, the CCS server registers a start-up command only for the controller POA but not for the thermometer and thermostat POAs. In that case, only requests to the controller, but not thermometers and thermostats, will result in automatic activation of the server.
Registration of a start-up command is optional. For example, the Stock and Payroll servers in Table 14.1 do not have a start-up command. Absence of a start-up command means that these servers will not be started by the implementation repository on demand. Instead, they must be started by hand.[2]
[2] Earlier versions of the CORBA specification used to call such servers persistent servers. Unfortunately, the term persistent as applied to servers had nothing to do with persistent IORs. Instead, the term denoted a server that must be started manually. Because of the potential confusion with persistent references, the term persistent server no longer exists in the specification (but you may come across it in older literature on CORBA).
Also note that the server that is started by the implementation repository need not run on the same machine as the repository itself. For example, the CCS server is started on a different machine via the remote shell. Using rsh to start a server remotely is only one possible option. Some ORBs also allow you to directly nominate a host for a server, and the ORB takes care of starting the server on that host for you. In addition, some ORBs also allow you to specify a specific port number for the server to use.
Host and port
This column records the address at which a server is currently running. No entry in this column indicates that the server is currently down.
Note that if a server uses multiple POAs, different POAs may be listening for requests on the same port or may use different ports. The choice depends on your ORB vendor. Some ORBs map all POAs in a server to the same port number, whereas others assign a different port to each POA or POA manager. The choice does not affect how you write your server code. The main point of interest is that for each instantiated POA, the
555

IT-SC book: Advanced CORBA® Programming with C++
implementation repository knows at what host and port that POA listens for incoming requests.
ORBs provide an administrative command that allows you to populate the implementation repository to inform it of the logical server name, the names of the POAs used by that server, and a command line if the server is to be started on demand.
14.4.3 Location Domains
Every server that uses indirect binding for persistent references must know where to find its implementation repository. Depending on the ORB, the server locates the implementation repository via environment variables, configuration files, or commandline options. The important point is that every server knows the host and port number of its repository.
Servers that are configured to use the same implementation repository are said to be in the same location domain. In effect, location domains are groups of machines or server processes, and all machines or server processes in the same location domain create object references that are bound via the same repository. The repository can typically run anywhere and not just on the same machine as the server processes it looks after (although some ORBs impose such a restriction). A particular location domain can encompass only a single machine or server, or it can contain multiple machines and servers. We discuss location domains in more detail in Section 14.5)
14.4.4 Interactions between Server and Implementation Repository
When a server process starts up, it looks in its configuration information for the host and port number of its implementation repository and connects to the repository. It then sends a message containing the name of the server's host to the implementation repository. This informs the repository on which machine the server was started; it may not be the same machine every time.
For every new persistent POA created by the server, the server sends a message to the implementation repository that contains the POA name and the port number at which that POA listens for requests. Conversely, whenever a POA is destroyed, the server informs the repository that this POA is no longer accepting requests. When a server shuts down (typically when its event loop terminates), it also informs the implementation repository that the server can no longer process requests.
The net effect is that the implementation repository knows at all times which servers are running where, which POAs are active, and at what port number each POA is listening. Typically, implementation repositories also implement a number of mechanisms to deal with various failures. For example, a high-quality repository will detect whether a server has crashed and will deal with failures such as loss of connectivity.
556

IT-SC book: Advanced CORBA® Programming with C++
The details of the interactions between an implementation repository and its servers and POAs are complex and vendor-specific. For this reason, we do not fully elaborate all the error recovery scenarios here. Instead, we present the general principles of how an ORB binds requests to servants.
14.4.5 Binding via an Implementation Repository
When a server creates a persistent reference, it sets the address and port number in the profile body of the IOR to point at the implementation repository that is responsible for the server. The server knows which host and port number to use by looking in its configuration information. In addition, the IOR contains the POA name and object ID as usual.
When a client first uses the IOR, it attempts to open a connection to the host and port found in the profile body. For indirect binding, the host and port are those of the implementation repository. If the repository is down and no connection can be established, the client-side run time raises a TRANSIENT exception in the client application code. The rationale for this is that the repository may come up again later, so if the client retries the operation after some time, binding may be successful.
If the client succeeds in connecting to the implementation repository, it simply sends whatever request was invoked by the application.[3] The implementation repository cannot process the request because the actual target object lives in a different server process. However, because the server and the implementation repository use the same ORB, the implementation repository knows how to decode the object key that was sent by the client with the request. The repository now unpacks the POA name from the object key and uses it as an index into its server table.
[3] See also Section 14.4.6, which discusses strategies for optimizing this behavior.
If the POA name cannot be found in the server table (because the server was never registered), the target server is completely unknown to the repository. In this case, the repository replies to the client with an OBJECT_NOT_EXIST exception, which is propagated up to the client application code.
If the POA name is known but the corresponding server is not running and does not have a registered command line for automatic start-up, the repository returns a TRANSIENT exception to the client, which is propagated up to the application code.
If the POA name is known and if the corresponding server is not running but has a command line registered, the repository starts the server process by executing the command. It then waits for messages from the server that indicate the server's host and the port number for the POA used by the request. These messages not only inform the repository of the POA's address details but also let it know that the POA is ready to accept requests.
557

IT-SC book: Advanced CORBA® Programming with C++
If the server is running (possibly after being started first), the repository returns a Reply message with a reply_status of LOCATION_FORWARD to the client (see Section
13.4.2). In the body of this reply, the repository returns another object reference to the client. The repository constructs that IOR by creating a new profile body that contains the actual host and port of the server along with the original POA name and object ID.
The client now has a new object reference and restarts the binding process from scratch by opening a connection to the host and port indicated in the new reference's profile and sending the request a second time. Because the implementation repository returned the current addressing information of the actual server, the client sends the request to the correct server on this second attempt and the request is bound to its servant as with transient references.
Figure 14.1 illustrates the sequence of interactions for a reference to the controller object, assuming that the server is registered as shown in Table 14.1. The diagram assumes that the implementation repository runs on machine coco at port 2133 and that the CCS server is not running when the client invokes the request. The sequence of steps during binding is as follows.
Figure 14.1 Binding of a persistent reference via the implementation repository with automatic server start-up.
Step 1.
The client invokes the find operation on the controller. This results in the client-side run time opening a connection to the address found in the controller IOR, which is the address of the repository. With the request, the client sends the object key (which contains the POA name and the object ID—controller and C1 in this example).
Step 2.
558

IT-SC book: Advanced CORBA® Programming with C++
The repository uses the POA name (controller) to index into its server table and finds that the server is not running. Because the POA has a registered command, the repository executes the command to start the server.
Step 3.
The server sends messages that inform the repository of its machine name (bobo), the names of the POAs it has created and their port numbers (controller at 1799), and the fact that it is ready to accept requests.
Step 4.
The implementation repository constructs a new object reference that contains host bobo, port number 1799, and the original object key and returns in a LOCATION_FORWARD reply.
Step 5.
The client opens a connection to bobo at port 1799 and sends the request a second time.
Step 6.
The server uses the POA name to locate the POA that contains the servant for the request. The POA contains another table, the Active Object Map, which maps object IDs to the memory address of the corresponding C++ servant. (Not all POAs have an Active Object Map; depending on the activation policy, the POA may also invoke an applicationsupplied servant manager to locate the correct servant, or the POA may dispatch the request to a default servant. The point is that the object ID serves to identify the servant that handles the request.) After the server has identified the servant object, it dispatches the request to the servant.
Step 7.
The servant completes the find operation and returns its results, which are marshaled back to the client in a Reply message.
As you can see, indirect binding uses the implementation repository as a location broker that returns a new IOR to the client that points at the current server location. The CORBA specification does not limit indirection to a single level. Instead, it requires a client to always respond to a LOCATION_FORWARD reply by attempting to send another request. Allowing multiple LOCATION_FORWARD replies permits more-complex repository designs, such as federated repositories, which distribute the binding load over a number of physical servers. (To the best of our knowledge, no ORBs implement federated repositories at the time of writing.)
14.4.6 Binding Optimizations
The indirect binding scenario we show in Section 14.4.5 can be optimized in a number of ways depending on your ORB and whether the client holds a reference to an object in the same ORB or another vendor's ORB. Note that the optimizations we outline here are not required by CORBA, so whether they are present in your ORB is vendordependent.
Explicit Location Resolution
559

IT-SC book: Advanced CORBA® Programming with C++
When a client opens a connection and sends a request, it typically has no idea whether the connection leads to the implementation repository (and binding will be indirect) or whether the connection leads straight to the actual server (and binding will be direct). The client sends the request that was invoked by the application in either case.
If a request contains in or inout parameters that are large (larger than a few hundred bytes), indirect binding wastes bandwidth. During indirect binding, the client sends in and inout parameters to the repository with the initial request. The repository ignores the parameter values because it requires only the object key to return a new IOR to the client, and the client transmits the parameter values a second time when it sends the request to the actual server at the forwarding location.
To avoid this repeated marshaling of parameters, a client can explicitly resolve the location of a server by sending a LocateRequest message. The body of a LocateRequest message contains only the object key. If the parameter values are large, this approach can save considerable bandwidth. A server that receives a LocateRequest message replies to the client with a LocateReply message.
If the client sends a LocateRequest message to the implementation repository, the repository resolves the request to a server location as usual and returns another IOR in the
LocateReply message.
If the client sends a LocateRequest message to the actual server that implements the object, the server returns a LocateReply message with a special status that indicates that the client has already reached the correct location.
Many ORBs always use this optimization and unconditionally send a LocateRequest message (instead of sending a complete request) whenever they encounter an IOR that has not yet been bound: for requests with large parameters, the LocateRequest message saves bandwidth; for requests with small parameters, sending a LocateRequest message is no less efficient than sending a Request message but simplifies the ORB implementation.
The only disadvantage of always sending an explicit LocateRequest first is that binding of transient IORs requires two messages instead of a single message. However, this is rarely a problem in practice because, in general-purpose ORBs, most IORs are persistent. (At any rate, a LocateRequest message is sent only for the first operation invocation on an object, so the actual performance difference is negligible.)
Avoidance of Indirect Binding
Indirect binding requires the client to always contact the implementation repository whenever a reference is used for the first time. After the reference has been bound, subsequent requests do not involve the implementation repository because the client
560

IT-SC book: Advanced CORBA® Programming with C++
already has an open connection to the server implementing the object and therefore knows how to reach the object implementation.
However, in large systems, the indirection via the implementation repository during dispatch of the first request on an IOR can slow a system down considerably. Not only does indirection require additional bandwidth, but it also can cause the repository to become a bottleneck. If there are many clients in the system, the repository may not be able to keep up with the binding requests and so may limit overall throughput.
If a client receives a reference created by another vendor's ORB, the client has no choice except to follow the normal binding protocol. The client has no idea how the object key encodes things such as the POA name (the object for the reference may not even be implemented using the POA). However, if the client receives an object reference that was created by the same ORB, it knows how to decode the object key. If the ORB uses multicomponent profiles, the IOR can carry a reliable identification of the ORB vendor and model.
This knowledge is valuable to the client-side run time because it can extract the POA name from the object key inside the IOR. If the client has previously bound a reference to an object in the same POA, it need not send the request to the implementation repository. Instead, it can cache which POA names belong to which connection and send the request directly to the correct server.
Caching the Server Birth Address
Normally, a server simply writes the address of the implementation repository into the profile body of each persistent reference. If an ORB uses multicomponent profiles, the server can additionally embed its own host and port number (known as the server birth address) in one of the components of the object key. When a client written for the same ORB receives the reference, it can extract the server birth address from the reference and attempt to connect directly to the server.
The server may no longer be running at the address it used when the reference was created. In that case, the attempt to reach the server at its birth address fails and the client then rebinds using the implementation repository.
The birth address optimization reduces the load on the implementation repository, especially if servers tend to be long-lived. The optimization is particularly useful for servers that are always started on the same port number (many implementation repositories offer this as an option). Of course, a server may eventually move to a different host or port number, perhaps months later. To avoid futile attempts to reach a server at its birth address on the first call via each reference, the client can maintain a table of birth addresses that are known to be stale. With such a table, a non-functional birth address will be tried only once.
Note that the client cannot update a stale birth address in a reference after it has learned the new location of the server from the repository. Doing this would be useful—for
561

IT-SC book: Advanced CORBA® Programming with C++
example, if the client in turn passes the reference to another process. However, the CORBA specification makes it illegal: no component of a CORBA system is allowed to modify any part of an object reference after the reference is created. The Object::hash operation guarantees that the hash value for a reference will not change while that reference denotes an existing object. If the client were to update the server birth address inside an IOR, the hash value would change.
Proprietary Protocols between Server and Implementation Repository
Figure 14.1 illustrates the messages exchanged between client, implementation repository, and server. Note that steps 1, 4, 5, and 7 use IIOP. In other words, all interactions that involve the client are portable whether client and server use the same vendor's ORB or different ORBs. On the other hand, steps 2 and 3 are restricted to the interaction between the server and its implementation repository. The server and the implementation repository always use an ORB from the same vendor, and their interactions are invisible to clients. Therefore, an ORB is free to use any protocol and communication mechanism it likes for these interactions.
Frequently, the implementation repository has an IDL interface that the server uses to send its address details. In other words, the implementation repository can appear as an ordinary CORBA object to the server, and the server communicates with it using IIOP. However, there are other options open to ORB vendors to improve performance.
Some ORBs use a UDP-based protocol between server and implementation repository. When the server starts up, instead of connecting to the repository using an address picked up from the ORB configuration, the server can send a UDP broadcast to dynamically acquire the address of the repository. One or more repositories that know the server's POA names and command line respond with their address details to the server, and the server chooses one of the repository addresses it receives to embed in IORs.
This mechanism not only simplifies configuration but also can provide simple fault tolerance. For example, if several repositories reply to the server, the server can create IORs with multiple profiles, one for each repository. The assumption is that the repositories are mirrors of each other, and if one repository becomes unreachable or crashes, the client has a second address in the IOR it can use to bind a request. (However, no commercial ORBs currently implement this feature.)
Using UDP to communicate with the repository can also be more efficient because UDP is a lightweight protocol with less overhead than IIOP. If the server and the implementation repository reside on the same host, they can also use a completely different transport for communication, such as a UNIX domain socket or shared memory, which can be faster in some environments.
Load Balancing
Some repositories offer a simple load-balancing mechanism. For example, a repository can monitor the load on a number of machines and start a server on the machine that has
562