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

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

implementations are derived from skeletons, the POA leaves the choice completely open letting you choose the preferable design.

For our example implementation, we use implementation inheritance. This results in the following class definition:

class Thermostat_impl :

public virtual POA_CCS::Thermostat, public virtual Thermometer_impl {

public:

 

 

// CORBA operations

 

get_nominal()

virtual CCS::TempType

virtual CCS::TempType

throw(CORBA::SystemException);

set_nominal(

 

 

CCS::TempType new_temp

 

 

) throw(

 

 

CORBA::SystemException,

 

 

CCS::Thermostat::BadTemp

 

 

);

// Constructor and destructor

Thermostat_impl(

anum,

CCS::AssetType

const char *

location,

CCS::TempType

nominal_temp

);

virtual ~Thermostat_impl() {}

private:

// Helper functions

CCS::TempType get_nominal_temp()

CCS::TempType set_nominal_temp(CCS::TempType new_temp) throw(CCS::Thermostat::BadTemp);

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

};

As with Thermometer_impl, we have added a constructor and a destructor along with private helper functions to handle the network API. We have hidden the copy constructor and the assignment operator.

10.7 Implementing the Thermostat Servant Class

The implementation of this class is mostly straightforward. As before, the implementation naturally falls into three sections for the helper functions, the IDL operations, and the constructor and destructor.

10.7.1 Thermostat_impl Helper Functions

357

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

The implementation of the get_nominal_temp helper simply invokes the corresponding ICP_get function. However, for set_nominal_temp, we must do extra work because ICP_set neither returns the previous nominal temperature nor reports error conditions at the level of detail we require:

// Helper function to get a thermostat's nominal temperature.

CCS::TempType Thermostat_impl:: get_nominal_temp()

{

short temp;

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

return temp;

}

// Helper function to set a thermostat's nominal temperature.

CCS::TempType Thermostat_impl::

set_nominal_temp(CCS::TempType new_temp) throw(CCS::Thermostat::BadTemp)

{

short old_temp;

//We need to return the previous nominal temperature,

//so we first read the current nominal temperature before

//changing it.

if (ICP_get(

m_anum, "nominal_temp", &old_temp, sizeof (old_temp) ) != 0) {

abort();

}

// Now set the nominal temperature to the new value. if (ICP_set(m_anum, "nominal_temp", &new_temp) != 0) {

//If ICP_set() failed, read this thermostat's minimum

//and maximum so we can initialize the BadTemp exception. CCS::Thermostat::BtData btd;

ICP_get(

m_anum, "MIN_TEMP",

&btd.min_permitted, sizeof(btd.min_permitted)

); ICP_get(

m_anum, "MAX_TEMP",

&btd.max_permitted, sizeof(btd.max_permitted)

);

btd.requested = new_temp; btd.error_msg = CORBA::string_dup(

new_temp > btd.max_permitted ? "Too hot" : "Too cold"

);

throw CCS::Thermostat::BadTemp(btd);

}

358

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

return old_temp;

}

Note that set_nominal_temp first reads the current nominal temperature so that it can return the previous nominal temperature to the caller. If ICP_set fails, the function reads the minimum and maximum permissible settings from the device and uses that data to initialize and throw a BadTemp exception.

10.7.2 Thermostat_impl IDL Operations

Given the helper functions we just defined, the implementation of the IDL operations of Thermostat_impl is trivial. The operations simply forward the call to the corresponding helper:

CCS::TempType Thermostat_impl::

get_nominal() throw(CORBA::SystemException)

{

return get_nominal_temp();

}

// IDL set_nominal operation.

CCS::TempType Thermostat_impl::

set_nominal(CCS::TempType new_temp) throw(CORBA::SystemException, CCS::Thermostat::BadTemp)

{

return set_nominal_temp(new_temp);

}

10.7.3 Thermostat_impl Constructor and Destructor

The destructor of Thermostat_impl has an empty inline definition (all the work is done by the base class destructor). The constructor passes the relevant parameters to its base class constructor and initializes the nominal temperature of the thermostat:

// Constructor.

 

Thermostat_impl::

 

Thermostat_impl(

anum,

CCS::AssetType

const char *

location,

CCS::TempType

nominal_temp

) : Thermometer_impl(anum, location)

{

//Base Thermometer_impl constructor does most of the

//work, so we need only set the nominal temperature here. set_nominal_temp(nominal_temp);

359

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

}

10.8 Designing the Controller Servant Class

Designing the controller servant requires a bit more effort, mainly because the ICP API does not give us a direct implementation of the list, change, and find operations. This immediately implies that the controller servant must keep track of known devices itself because there is no way to ask the network which devices are currently on-line. We use a private data member called m_assets to keep a collection of instantiated servants. The member is an STL map defined as follows:

class Controller_impl : public virtual POA_CCS::Controller { public:

//...

private:

//Map of known servants

typedef map<CCS::AssetType, Thermometer_impl *> AssetMap; AssetMap m_assets;

// ...

};

m_assets maps asset numbers to servant pointers and allows us to list the known devices as well as to search for devices having particular attribute values.

The class definition for the controller servant must provide declarations for the three IDL operations list, change, and find. In addition, we add the public helper functions add_impl and remove_impl so that the constructor and destructor of thermometer servants can keep the controller's list of devices up-to-date. The controller's constructor and destructor are empty in this design, and, as usual, we hide the copy constructor and assignment operator. This results in the following class definition:

class Controller_impl : public virtual POA_CCS::Controller { public:

// CORBA operations

virtual CCS::Controller::ThermometerSeq *

list() throw(CORBA::SystemException); virtual void

find(CCS::Controller::SearchSeq & slist) throw(CORBA::SystemException);

virtual void change(

const CCS::Controller::ThermostatSeq & tlist, CORBA::Short delta

) throw( CORBA::SystemException, CCS::Controller::EChange

);

// Constructor and destructor Controller_impl() {}

virtual ~Controller_impl() {}

360

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

//Helper functions to allow thermometers and

//thermostats to add themselves to the m_assets map

//and to remove themselves again.

void

add_impl(CCS::AssetType anum, Thermometer_impl * tip);

void

remove_impl(CCS::AssetType anum);

private:

// Map of known servants

typedef map<CCS::AssetType, Thermometer_impl *> A ssetMap; AssetMap m_assets;

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

//...

};

The m_assets map allows us to easily search for devices by asset number using the STL standard find algorithm. However, the IDL find operation also requires searching by model and location. An easy way to search through a map is to use an STL function object that evaluates a predicate for use by the STL standard find_if algorithm. Because both model and location are string-valued attributes, we can use a single function object to search for either attribute value. The StrFinder class is a nested class of Controller_impl and does double duty to search for devices either by model or location, depending on the search criterion passed to its constructor. (For simplicity, we have inlined the class definition.)

class Controller_impl : public virtual POA_CCS::Controller { public:

//...

private:

//...

//Function object for the find_if algorithm to search for

//devices by location and model string.

class StrFinder {

 

public:

 

StrFinder(

sc,

CCS::Controller::SearchCriterion

const char *

str

) : m_sc(sc), m_str(str) {}

 

bool operator()(

pair<const CCS::AssetType, Thermometer_impl *> & p ) const

{

switch (m_sc) {

case CCS::Controller::LOCATION:

return strcmp(p.second->location(), m_str) == 0; break;

case CCS::Controller::MODEL:

return strcmp(p.second->model(), m_str) == 0; break;

361