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

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

As with all servant classes, we hide the copy constructor and assignment operator for the class because copy and assignment do not usually make sense for servants.

These points result in a class definition for Thermometer_impl as follows:

class Controller_impl;

class Thermometer_impl : public virtual POA_CCS::Thermometer {

public:

 

// CORBA attributes

model()

virtual CCS::ModelType

virtual CCS::AssetType

throw(CORBA::SystemException);

asset_num()

virtual CCS::TempType

throw(CORBA::SystemException);

temperature()

virtual CCS::LocType

throw(CORBA::SystemException);

location()

virtual void

throw(CORBA::SystemException);

location(const char * loc)

 

throw(CORBA::SystemException);

// Constructor and destructor Thermometer_impl(CCS::AssetType anum, const char * location); virtual ~Thermometer_impl();

static Controller_impl *

m_ctrl; // My controller

protected:

 

m_anum; // My asset number

CCS::AssetType

 

private:

 

 

// Helper functions

 

CCS::ModelType

get_model();

 

CCS::TempType

get_temp();

 

CCS::LocType

get_loc();

 

void

set_loc(const char * new_loc);

// Copy and assignment not supported Thermometer_impl(const Thermometer_impl &); void operator=(const Thermometer_impl &);

};

10.5 Implementing the Thermometer Servant Class

The implementation of Thermometer_impl naturally falls into three sections for the helper functions, the IDL operations, and the constructor and destructor.

10.5.1 Thermometer_impl Helper Functions

The four helper functions encapsulate the ICP API to make life a little easier for the remainder of the implementation. We could do without the helper functions. However, creating such helper functions—or, even better, helper classes—typically goes a long

352

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

way toward code maintainability, particularly for complex APIs. In this example, the implementation of the helper functions is trivial:

// Helper function to read the model string from a device.

CCS::ModelType Thermometer_impl:: get_model()

{

char buf[32];

if (ICP_get(m_anum, "model", buf, sizeof(buf)) != 0) abort();

return CORBA::string_dup(buf);

}

// Helper function to read the temperature from a device.

CCS::TempType Thermometer_impl:: get_temp()

{

short temp;

if (ICP_get(m_anum, "temperature", &temp, sizeof(temp)) != 0) abort();

return temp;

}

// Helper function to read the location from a device.

CCS::LocType Thermometer_impl:: get_loc()

{

char buf[32];

if (ICP_get(m_anum, "location", buf, sizeof(buf)) != 0) abort();

return CORBA::string_dup(buf);

}

// Helper function to set the location of a device. void

Thermometer_impl:: set_loc(const char * loc)

{

if (ICP_set(m_anum, "location", loc) != 0) abort();

}

Each function reads or writes the corresponding attribute using the ICP API. Note that in our server, errors from the ICP API are assertion failures. Of course, for a more realistic server, you should probably log an error message instead of terminating the entire server process.

10.5.2 Thermometer_impl IDL Operations

353

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

Implementing the attributes of Thermometer is trivial because it requires only a call to the corresponding helper function:

// IDL model attribute.

CCS::ModelType Thermometer_impl::

model() throw(CORBA::SystemException)

{

return get_model();

}

//IDL asset_num attribute. CCS::AssetType Thermometer_impl::

asset_num() throw(CORBA::SystemException)

{

return m_anum;

}

//IDL temperature attribute.

CCS::TempType Thermometer_impl::

temperature() throw(CORBA::SystemException)

{

return get_temp();

}

// IDL location attribute accessor.

CCS::LocType Thermometer_impl::

location() throw(CORBA::SystemException)

{

return get_loc();

}

// IDL location attribute modifier.

void Thermometer_impl::

location(const char * loc) throw(CORBA::SystemException)

{

set_loc(loc);

}

10.5.3 Thermometer_impl Constructor and Destructor

As you saw in Section 10.3, the ICP API does not have functionality to directly support the list operation on the controller. This forces us to keep track of the devices known to the network ourselves. As you will see in Section 10.8, we do this by keeping an STL map in a private data member of the controller implementation; this map allows us to locate each instantiated servant by its asset number.

354

// Prevent exceptions from escaping

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

When the server creates a Thermometer_impl servant, the constructor of the class calls the controller's add_impl member function to add the servant to the controller's map. In addition, the constructor initializes the protected m_anum data member, sets the location of the device, and marks the device as on-line. Conversely, the destructor removes the servant from the controller's map by calling remove_impl and marks the device as off-line.

Controller_impl * Thermometer_impl::m_ctrl; // static member

// Constructor.

 

 

Thermometer_impl::

 

 

Thermometer_impl(

anum,

 

CCS::AssetType

 

const char *

location

 

) : m_anum(anum)

 

 

{

 

// Mark device as on-line

if (ICP_online(anum) != 0)

abort();

 

// Set location

set_loc(location);

 

m_ctrl->add_impl(anum, this);

// Add self to map

}

 

 

// Destructor.

Thermometer_impl:: ~Thermometer_impl()

{

try {

m_ctrl->remove_impl(m_anum); // Remove self from map ICP_offline(m_anum); // Mark device as off-line

} catch (...) { abort();

}

}

Note that the static data member m_ctrl is initialized in main after the controller servant is instantiated (see Section 10.10).

10.6 Designing the Thermostat Servant Class

The Thermostat interface is derived from Thermometer, and we are implementing both thermometers and thermostats in the same server. Whenever we implement a derived interface in the same address space as its base interface, we must make a design decision. We can use implementation inheritance by inheriting the base class's implementation in the derived class, as shown in Figure 10.1. The main advantage of the structure in Figure 10.1 is that we need implement only the operations of

Thermostat in the derived Thermostat_impl class. Because Thermostat_impl inherits from Thermometer_impl, there is no need to implement the attributes of the Thermometer base interface in the derived servant.

355

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

Figure 10.1 Implementation inheritance (generated classes are shaded).

The alternative is to use interface inheritance, which is shown in Figure 10.2. Note that in Figure 10.2, Thermostat_impl does not inherit from Thermometer_impl. This approach means that Thermostat_impl must implement six virtual functions: four to implement the attributes of Thermometer, and two to implement the operations of Thermostat.

Figure 10.2 Interface inheritance (generated classes are shaded).

Which approach is more suitable depends on your design and your requirements. It is possible that the implementation of thermometers differs considerably from the one for thermostats, for example, if thermometers and thermostats use different protocols (and therefore different APIs). In that case, interface inheritance will be the better approach.

On the other hand, if both thermometers and thermostats are implemented using the same API, there is no good reason not to reuse the base class implementation and choose implementation inheritance.

We point out the difference between the two approaches here because it typically comes as a surprise to C++ programmers. In C++, implementation inheritance is the default, and you must make special efforts to get interface inheritance only. In contrast, given how

356