Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Advanced CORBA Programming wit C++ - M. Henning, S. Vinoski.pdf
Скачиваний:
65
Добавлен:
24.05.2014
Размер:
5 Mб
Скачать

IT-SC book: Advanced CORBA® Programming with C++

Chapter 9. Server-Side C++ Mapping

9.1 Chapter Overview

This chapter describes how IDL interfaces map to C++ classes that support the creation and invocation of CORBA objects. Section 9.2 provides some general background on object adapters, specifically the POA, and the relationship between CORBA objects and programming language objects. We then devote several sections to covering how a simple CORBA object is implemented in C++. Following that, we present the details of the server-side C++ mapping in Section 9.7. In Section 9.8, we discuss issues related to using exceptions to indicate error conditions in your server implementations. Finally, in Section 9.9 we explain POA tie classes along with their advantages and disadvantages.

9.2 Introduction

As described in Section 2.3, CORBA objects take form within server applications. In a server, CORBA objects are implemented and represented by programming language functions and data. The programming language entities that implement and represent CORBA objects are called servants. Because servants essentially provide bodies for CORBA objects, they are said to incarnate CORBA objects.

In CORBA, object adapters link the world of CORBA objects to the world of programming language servants. Conceptually, object adapters mediate between the ORB and programming language servants. They provide services for the creation of CORBA objects and their object references and for dispatching requests to the appropriate servants. The standard object adapter defined in the CORBA specification is the Portable Object Adapter (POA). It provides features necessary to allow programming language servants to be portable among ORBs supplied by different vendors. A server application may contain multiple POA instances to support CORBA objects with different characteristics or to support multiple servant implementation styles. However, all server applications have at least one POA called the Root POA. In this chapter we introduce only the basic usage of the Root POA needed to explain the server-side C++ mapping. More POA details are explained in Chapter 11.

Figure 9.1 shows a greatly simplified illustration of the general relationships between an ORB, a POA Manager, a POA, and servants. Conceptually, requests for CORBA objects residing in the server application are sent from a client and arrive at the server ORB, which dispatches them to the POA in which the target object was created. The POA then further dispatches the request to the servant incarnating the target object. The servant carries out the request and returns any out and return values through the POA and ORB to the client.

313

IT-SC book: Advanced CORBA® Programming with C++

Figure 9.1 Relationships between ORB, POA Manager, POA, and servants.

Implied in Figure 9.1 is the event handling model used by server applications. A server cannot accept any incoming requests until it tells its ORB to start listening for them. In addition, because a single server application may contain multiple POAs, the flow of requests into each POA is controlled by a POAManager object associated with that POA. In addition to letting requests flow into a POA, a POAManager can queue requests for later dispatch or can discard them.

Ultimately, each CORBA request received by a server application must be processed by a servant. The main function of the server-side C++ mapping is to allow applications to implement CORBA objects using C++ objects as servants. Because CORBA objects consist of interfaces, operations, and attributes, the server-side mapping specifies only how these IDL features appear in C++. All other IDL features have the same mapping on the server side as they do on the client side.

Server-side C++ classes that correspond to IDL interfaces are called skeleton classes. They correspond to client-side proxy classes and are generated by IDL compilers into C++ source files that you compile into your application. Unlike their client-side counterparts, skeleton classes are intended to serve as base classes for applicationspecific classes. The term skeleton refers to the fact that these classes supply only a support framework, or skeleton, for CORBA object implementations. By deriving servant classes from these skeleton classes, applications extend and complete the skeleton framework, thus allowing for the creation and incarnation of CORBA objects.

9.3 Mapping for Interfaces

The server-side C++ mapping generates a separate skeleton class for each IDL interface. Similar to the way IDL compilers generate header files to be included on the client side (as described in Section 8.4), IDL compilers normally generate header files that contain skeleton class definitions. The names and contents of these generated files differ among ORB implementations, but typically an IDL compiler emits both a header file and an implementation file. Consider the following simple interface:

interface MyObject { long get_value();

};

314

IT-SC book: Advanced CORBA® Programming with C++

The generated header file contains the following skeleton class definition:

class POA_MyObject : public virtual PortableServer::ServantBase { public:

virtual CORBA::Long get_value() throw(CORBA::SystemException) = 0;

// ...

};

For now, we have omitted a number of details of this class. The important points to note now are as follows.

The name of the generated skeleton class POA_MyObject matches the MyObject IDL interface except for its POA_ prefix. The POA_ prefix serves to separate the names of server-side C++ classes from those generated for the client side. This namespace separation is important because most non-trivial CORBA applications are both servers for their own objects and clients of other objects. Without the difference in names, attempts to link client-side and server-side C++ classes in the same application would result in link-time errors because of multiply defined symbols.

Note that it is only the name of the outermost scope that receives the POA_ prefix. If MyObject were defined in module Mod, for example, the fully scoped name of its generated skeleton class would be POA_Mod::MyObject.

The skeleton class inherits from PortableServer::ServantBase, which is the common base class for all skeleton classes.

The skeleton class provides a get_value method that corresponds to the IDL get_value operation.

get_value is declared pure virtual, so the POA_MyObject skeleton class is an abstract base class that cannot be instantiated.

get_value includes an exception specification that limits the types of C++ exceptions it can legally throw. Exception specifications are always generated for server-side methods as opposed to methods declared in client-side proxy classes, in which exception specifications are optional. All methods that implement IDL operations can throw CORBA system exceptions, and this means that the CORBA::SystemException base class is included in all skeleton class exception specifications.

Later, we show some of the missing details of skeleton classes. ORBs typically also add implementation-specific member functions to skeleton classes. These functions are normally used by the object adapter to dispatch requests to the correct servant. You never need to call such ORB-specific functions yourself, so we do not show them and you can safely pretend that they do not exist.

315

IT-SC book: Advanced CORBA® Programming with C++

9.4 Servant Classes

To create a CORBA object of type MyObject, you must derive a servant class from the POA_MyObject class and implement all pure virtual methods. Consider the following servant class example:

#include "my_objectS.hh"

class MyObject_impl : public virtual POA_MyObject { public:

MyObject_impl(CORBA::Long init_val) : m_value(init_val) {}

virtual CORBA::Long get_value() throw(CORBA::SystemException);

private:

CORBA::Long m_value;

// copy and assignment not needed MyObject_impl(const MyObject_impl &); void operator=(const MyObject_impl &);

};

There are several important points to note about this servant class.

We assume that we use our IDL compiler to compile the file my_object.idl, containing the IDL definition of the MyObject interface, to produce the server-side header file my_objectS.hh. (The name of the header file is not standardized, so the exact name will vary depending on the IDL compiler you use.) We include this header file to obtain the declaration for the POA_MyObject base class.

The name chosen for the servant class, MyObject_impl, is entirely up to the application. It can be any name at all, as long as it does not clash with any names reserved by the C++ mapping, such as those beginning with POA_. We follow the convention of naming our servant classes with an _impl suffix so that we can tell by looking at the class name that it is a servant class.

The MyObject_impl class inherits from the POA_MyObject skeleton as a virtual base class and overrides the pure virtual get_value function. This makes MyObject_impl a concrete class that can be instantiated.

You are obliged to implement all inherited pure virtual functions in your servant class because otherwise the C++ compiler will not allow you to create instances of it. Beyond that, you can add whatever else you consider useful to support the implementation of your servant class. For example, you may want to add a constructor and destructor, additional member functions, or data members. You can also add a protected or private section. For this example, we have added a private data member called m_value of type CORBA::Long, and a constructor that initializes that member. We have also made the copy constructor and default assignment operator private, thereby disallowing copying of

316