Server-side mapping refers to the portability constraints for an object implementation written in C++. The term server is not meant to restrict implementations to situations in which method invocations cross-address space or machine boundaries. This mapping addresses any implementation of an Object Management Group (OMG) Interface Definition Language (IDL) interface.
Note: The information in this chapter is based on the Common Object Request Broker: Architecture and Specification, Revision 2.4.2, February 2001, published by the Object Management Group (OMG). Used with permission of the OMG.In the inheritance-based interface implementation approach, the implementation classes are derived from a generated base class based on the OMG IDL interface definition. The generated base classes are known as skeleton classes, and the derived classes are known as implementation classes. Each operation of the interface has a corresponding virtual member function declared in the skeleton class. The generated skeleton class is partially opaque to the programmer, though it will contain a member function corresponding to each operation in the interface. The signature of the member function is identical to that of the generated client stub class.To implement this interface using inheritance, a programmer must derive from this skeleton class and implement each of the operations in the OMG IDL interface. To allow portable implementations to multiple inheritances from both skeleton classes and implementation classes for other base interfaces without error or ambiguity, the Tobj_ServantBase class must be a virtual base class of the skeleton, and the PortableServer::ServantBase class must be a virtual base class of the Tobj_ServantBase class. The inheritance among the implementation class, the skeleton class, the Tobj_ServantBase class, and the PortableServer::ServantBase class must all be public virtual.The implementation class or servant must only derive directly from a single generated skeleton class. Direct derivation from multiple skeleton classes could result in ambiguous errors due to multiple definitions of the _this() operation. This should not be a limitation, however, since CORBA objects have only a single most-derived interface. C++ servants that are intended to support multiple interface types can utilize the delegation-based interface implementation approach. See Listing 15‑1 for an example of OMG IDL that uses interface inheritance.Listing 15‑1 OMG IDL That Uses Interface InheritanceListing 15‑2 Interface Class AFor the Portable Object Adapter (POA), the name of the skeleton class is formed by prepending the string “POA_” to the fully scoped name of the corresponding interface, and the class is directly derived from the servant base class Tobj_ServantBase. The C++ mapping for Tobj_ServantBase is as follows:The activate_object() and deactivate_object() member functions are described in detail in the sections Tobj_ServantBase:: activate_object() and Tobj_ServantBase::_add_ref().Listing 15‑3 Skeleton Class for Interface AIf interface A were defined within a module rather than at global scope (for example, Mod::A), the name of its skeleton class would be POA_Mod::A. This helps to separate server application skeleton declarations and definitions from C++ code generated for the client.To implement this interface using inheritance, you must derive from this skeleton class and implement each of the operations in the corresponding OMG IDL interface. An implementation class declaration for interface A would take the form shown in Listing 15‑4.Listing 15‑4 Interface A Implementation Class DeclarationIn the delegation-based approach, the implementation does not inherit from a skeleton class. Instead, the implementation can be coded as required for the application, and a wrapper object will delegate upcalls to that implementation. This “wrapper object,” called a tie, is generated by the IDL compiler, along with the same skeleton class used for the inheritance approach. The generated tie class is partially opaque to the programmer, though, like the skeleton, it provides a method corresponding to each OMG IDL operation for the associated interface. The name of the generated tie class is the same as the generated skeleton class with the addition that the string _tie is appended to the end of the class name.An instance of the tie class is the servant, not the C++ object being delegated to by the tie object, that is passed as the argument to the operations that require a Servant argument. It should also be noted that the tied object has no access to the _this( ) operation, nor should it access data members directly.A type-safe tie class is implemented using C++ templates. The code shown in Listing 15‑5 illustrates a tie class generated from the Derived interface in the previous OMG IDL example.Listing 15‑5 Tie Class Generated from the Derived InterfaceAs you can see, the tie class contains definitions for the op1 and op2 operations of the interface that assume that the legacy class has operations with the same signatures as those given in the IDL. If this is the case, you can use the tie class file as is, letting it delegate exactly. It is more likely, however, that the legacy class will not have identical signatures or you may have to do more than a single function call. In that case, it is your job to replace the code for op1 and op2 in this generated code. The code for each operation typically makes invocations on the legacy class using the tie class variable _ptr, which contains the pointer to the legacy class. For example, you might change the following lines:An instance of this template class performs the task of delegation. When the template is instantiated with a class type that provides the operation of the Derived interface, then the POA_Derived_tie class will delegate all operations to an instance of that implementation class. A reference or pointer to the actual implementation object is passed to the appropriate tie constructor when an instance of the POA_Derived_tie class is created. When a request is invoked on it, the tie servant will just delegate the request by calling the corresponding method on the implementation class.The signature of an implementation member function is the mapped signature of the OMG IDL operation. Unlike the client-side mapping, the OMG specifies that the function header for the server-side mapping include the appropriate exception specification. An example of this is shown in Listing 15‑6.Listing 15‑6 Exception SpecificationSince all operations and attributes may raise CORBA system exceptions, CORBA::SystemException must appear in all exception specifications, even when an operation has no raises clause.Within a member function, the “this” pointer refers to the implementation object’s data as defined by the class. In addition to accessing the data, a member function may implicitly call another member function defined by the same class. An example of this is shown in Listing 15‑7.Listing 15‑7 Calling Another Member Function