18
The mapping does not specify how the implementation class is related to any other classes, including the generated class for the interface. This approach allows implementations to use either inheritance or delegation and to include other features from the ORB implementation (such as choosing a default transport representation). The examples in this chapter provide sample solutions for defining implementation classes. CORBA-compliant implementations are not required to use these alternatives.
18.2 Implementing Operations
The signature of an implementation member function is the mapped signature of the OMG IDL operation. Unlike the client side, the server-side mapping requires that the function header include the appropriate exception (throw) specification. This requirement allows the compiler to detect when an invalid exception is raised, which is necessary in the case of a local C++-to-C++ library call (otherwise the call would have to go through a wrapper that checked for a valid exception). For example:
// IDL
// C++
interface A
{
exception B {};
void f() raises(B);
};
class MyFavoriteImplementationOfA ...
{
public:
class B : public UserException {};
void f() throw(B);
...
};The mapping provides two operations that are accessible from within the body of a member function: _this() and _boa(). The _this() function returns an object reference (T_ptr) for the target object. The _boa() function returns a BOA_ptr to the appropriate BOA object. The implementation may not assume where the _boa() function is defined, only that it is available within the member function. The _boa() function could be a member function, a static member function, or a static function defined in a namespace that is accessible from the member functions of the implementation. The return values of _this() and _boa() must be released via CORBA::release().
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. For example:
// IDL
interface A
// C++
{
void f();
void g();
};
class MyFavoriteImplementationOfA ...
{
public:
void f();
void g();
private:
long x_;
};
void MyFavoriteImplementationOfA::f()
{
x_ = 3;
g();
} 18.3 Examples
As with other examples shown in this mapping, the following examples are not meant to mandate a particular implementation. Rather, they show some of the implementations that are possible in order to help clarify the descriptions of the mapping.
18.3.1 Using C++ Inheritance for Interface Implementation
Implementation classes can be 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 signature of the member function is identical to that of the generated client stub class. The implementation class provides implementations for these member functions. The BOA invokes the methods via calls to the skeleton class's virtual functions.
The following OMG IDL interface will be used in all the examples in this section:
// IDL
interface A
{
short op1();
void op2(in long l);
};An IDL compiler generates an interface class A for this interface. This class contains the C++ definitions for the typedefs, constants, exceptions, attributes, and operations in the OMG IDL interface. It has a form similar to the following:
class A : public virtual CORBA::Object
{
public:
virtual Short op1() = 0;
virtual void op2(Long l) = 0;
...
};Some ORB implementations might not use public virtual inheritance from CORBA::Object, and might not make the operations pure virtual, but the signatures of the operations will be the same.
On the server side, a skeleton class can be generated. This class is partially opaque to the programmer, though it will contain a member function corresponding to each operation in the interface.
class _sk_A : public A
{
public:
// ...server-side implementation-specific detail
// goes here...
virtual Short op1() = 0;
...
};To implement this interface, a programmer must derive from this skeleton class and implement each of the operations in the OMG IDL interface. An implementation class declaration for interface A would take the form:
class A_impl : public _sk_A
{
public:
Short op1();
...
}; 18.3.2 Using Delegation for Interface Implementation
Inheritance is not always the best solution for implementing interfaces. Using inheritance from the OMG IDL-generated classes forces a C++ inheritance hierarchy on the implementor. Sometimes, the overhead of such inheritance is too high. For example, implementing OMG IDL interfaces with existing legacy code might be impossible if inheritance from some global class was enforced.
In some cases delegation can be used to good effect to solve this problem. Rather than inheriting from some global class, the implementation can be coded in any way at all, and some wrapper classes will delegate upcalls to that implementation. This section describes how this can be achieved in a type-safe manner using C++ templates.
For the examples in this section, the OMG IDL interface from Section 18.3.1 will again be used:
// IDL
interface A
{
short op1();
void op2(in long l);
};An IDL compiler will generate a (possibly abstract) class A in C++ defining this interface.
Normally, the server implementor will have to derive from this class or some related class to implement a server-side object. However, the an IDL compiler could generate another class, called a tie. This class is partially opaque to the application programmer, though like the skeleton, it provides a method corresponding to each OMG IDL operation.
template <class T>
class _tie_A : public A
{
public:
_tie_A(T &t);
Short op1();
void op2(Long l);
...
};This class performs the task of delegation. When the template is instantiated with a class that supports the operations of A, then the _tie_A class will delegate all operations to that implementation class. When an instance of this class is created, then a reference to the actual implementation class is passed to the constructor. Typically the implementation will just call the corresponding method in the implementation class via this reference.
template <class T>
class _tie_A : public A
{
public:
_tie_A(T &t) : _ref(t) {}
Short op1() {return _ref.op1();}
void op2(Long l) {_ref.op2(l);}
private:
T &_ref;
}; 18.4 Mapping of Dynamic Skeleton Interface to C++
Section 5.3, "Dynamic Skeleton Interface: Language Mapping," on page 5-3 contains general information about mapping the Dynamic Skeleton Interface to programming languages.
This section contains the following information:
// C++
in
parameters in the NVList, or the context returned by ctx(). Similarly, data allocated by the DIR and handed to the ORB (the NVList parameters, any result value, and exception values) is freed by the ORB rather than by the DIR.
out
ones (their values are null pointers at first), for the operation. This allows the ORB to verify that the correct parameter types have been provided before filling their values in, but does not require it to do so. It also relieves the ORB of all responsibility to consult the interface repository, promoting high performance implementations.
out
values, including the return side of inout
values, to the ORB by modifying the NVList after params() has been called.
OperationDef
information. This allows it to create an NVList and fill in the TypeCodes for all the operation's parameters: the in
values, out
values, and inout
values. Then the DIR calls params()
with that NVList. At this point, the value pointers for all in
and inout
(the input side only) parameters in that NVList are valid.
result()
has been called.
// C++