CORBA Programming Reference

Server-side Mapping

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.

Implementing Interfaces

To define an implementation in C++, you define a C++ class with any valid C++ name. For each operation in the interface, the class defines a nonstatic member function with the mapped name of the operation (the mapped name is the same as the OMG IDL identifier).

The server application mapping specifies two alternative relationships between the implementation class supplied by the application and the generated class or classes for the interface. Specifically, the mapping requires support for both inheritance-based relationships and delegation-based relationships. Conforming applications may use either or both of these alternatives. Oracle Tuxedo CORBA supports both inheritance-based and delegation-based relationships.

Inheritance-based Interface Implementation

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 implementationclasses. 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.

On the server side, a skeleton class is generated. This class is partially opaque to the programmer, though it does contain a member function corresponding to each operation in the interface.

For 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:

If 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.

Delegation-based Interface Implementation

The delegation-based interface implementation approach is an alternative to using inheritance when implementing CORBA objects. This approach is used when the overhead of inheritance is too high or cannot be used. For example, due to the invasive nature of inheritance, implementing objects using existing legacy code might be impossible if inheritance for some global class were required. Instead, delegation can be used to solve these types of problems. Delegation is a more natural fit doing object implementations when the Process-Entity design pattern is used. In this pattern, the Process object would delegate operations onto one or more entity objects.

In 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.

This class definition is a template generated by the IDL compiler. You typically use it by first getting a pointer to the legacy class and then instantiating the tie class with that pointer. For example:

As 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 use of templates for tie classes allows the application developer to provide specializations for some or all of the template’s operations for a given instantiation of the template. This allows the application to use legacy classes for tied object types, where the operation signatures of the tied object will differ from that of the tie class.

Implementing Operations

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 Specification

// IDLinterface A{ exception B {}; void f() raises(B);};

// C++class MyA : public virtual POA_A{ public: void f(); ...};

Since 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.

Note:

Because of the differences in C++ compilers, it is best to leave out the "throw declaration" in the method signature. Some systems cause the application server to crash if an undeclared exception is thrown in a method that has declared the exceptions it will throw.

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.