diff options
Diffstat (limited to 'TAO/examples/Advanced/ch_18/server.cpp')
-rw-r--r-- | TAO/examples/Advanced/ch_18/server.cpp | 794 |
1 files changed, 794 insertions, 0 deletions
diff --git a/TAO/examples/Advanced/ch_18/server.cpp b/TAO/examples/Advanced/ch_18/server.cpp new file mode 100644 index 00000000000..17b74ff11fa --- /dev/null +++ b/TAO/examples/Advanced/ch_18/server.cpp @@ -0,0 +1,794 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_18 +// +// = FILENAME +// server.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the +// code provided in the book, "Advanced CORBA Programming with C++" +// by Michi Henning and Steve Vinoski. Copyright +// 1999. Addison-Wesley, Reading, MA. Used with permission of +// Addison-Wesley. +// +// Modified for TAO by Mike Moran <mm4@cs.wustl.edu> +// +// ============================================================================ + +#include <iostream> +#include <fstream> +#include <strstream> +#include "server.h" +#include <algorithm> +#include "icp.h" +#include "orbsvcs/CosNamingC.h" + +const char * Controller_oid = "Controller"; +const unsigned int DeviceLocator_impl::MAX_EQ_SIZE = 100; + +//---------------------------------------------------------------- + +template<class T> +typename T::_ptr_type +resolve_init (CORBA::ORB_ptr orb, const char * id) +{ + CORBA::Object_var obj; + try { + obj = orb->resolve_initial_references (id); + } + catch (const CORBA::ORB::InvalidName &) { + throw; + } + catch (const CORBA::Exception & e) { + std::cerr << "Cannot get initial reference for " + << id << ": " + //<< e + << std::endl; + throw 0; + } + assert (!CORBA::is_nil (obj.in ())); + + typename T::_var_type ref; + try { + ref = T::_narrow (obj.in ()); + } + catch (const CORBA::Exception & e) { + std::cerr << "Cannot narrow reference for " + << id << ": " + //<< e + << std::endl; + throw 0; + } + if (CORBA::is_nil (ref.in ())) { + std::cerr << "Incorrect type of reference for " + << id << std::endl; + throw 0; + } + return ref._retn (); +} + +//---------------------------------------------------------------- + +// Generic ostream inserter for exceptions. Inserts the exception +// name, if available, and the repository ID otherwise. + +#if 0 // This inserter is not needed for TAO. + +static ostream & +operator<< (ostream & os, const CORBA::Exception & e) +{ + CORBA::Any tmp; + tmp <<= e; + + CORBA::TypeCode_var tc = tmp.type (); + const char * p = tc->name (); + if (*p != '\0') + os << p; + else + os << tc->id (); + return os; +} + +#endif + +//---------------------------------------------------------------- + +// Helper function to create object references. + +static CCS::Thermometer_ptr +make_dref (PortableServer::POA_ptr poa, CCS::AssetType anum) +{ + // Convert asset number to OID. + ostrstream ostr; + ostr << anum << ends; + char * anum_str = ostr.str (); + PortableServer::ObjectId_var oid + = PortableServer::string_to_ObjectId (anum_str); + delete[] anum_str; + + // Look at the model via the network to determine + // the repository ID. + char buf[32]; + assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0); + const char * rep_id = strcmp (buf, "Sens-A-Temp") == 0 + ? "IDL:acme.com/CCS/Thermometer:1.0" + : "IDL:acme.com/CCS/Thermostat:1.0"; + + // Make a new reference. + CORBA::Object_var obj + = poa->create_reference_with_id (oid.in (), rep_id); + return CCS::Thermometer::_narrow (obj.in ()); +} + +//---------------------------------------------------------------- + +Controller_impl * Thermometer_impl::m_ctrl; // static member + +// Helper function to read the model string from a device. + +CCS::ModelType +Thermometer_impl:: +get_model () +{ + char buf[32]; + assert (ICP_get (m_anum, "model", buf, sizeof (buf)) == 0); + return CORBA::string_dup (buf); +} + +// Helper function to read the temperature from a device. + +CCS::TempType +Thermometer_impl:: +get_temp () +{ + short temp; + assert (ICP_get (m_anum, "temperature", &temp, sizeof (temp)) == 0); + return temp; +} + +// Helper function to read the location from a device. + +CCS::LocType +Thermometer_impl:: +get_loc () +{ + char buf[32]; + assert (ICP_get (m_anum, "location", buf, sizeof (buf)) == 0); + return CORBA::string_dup (buf); +} + +// Helper function to set the location of a device. + +void +Thermometer_impl:: +set_loc (const char * loc) +{ + assert (ICP_set (m_anum, "location", loc) == 0); +} + +// Constructor. + +Thermometer_impl:: +Thermometer_impl (CCS::AssetType anum) : m_anum (anum) +{ + m_ctrl->add_impl (anum, this); // Add self to controller's set +} + +// Destructor. + +Thermometer_impl:: +~Thermometer_impl () +{ + if (m_ctrl->exists (m_anum)) + m_ctrl->add_impl (m_anum, 0); // Clear servant pointer +} + +// 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 remove operation. + +void +Thermometer_impl:: +remove () throw (CORBA::SystemException) +{ + m_ctrl->remove_impl (m_anum); + assert (ICP_offline (m_anum) == 0); + //delete this; +} + +// IDL location attribute modifier. + +void +Thermometer_impl:: +location (const char *loc) throw (CORBA::SystemException) +{ + set_loc (loc); +} + +//---------------------------------------------------------------- + +// Helper function to get a thermostat's nominal temperature. + +CCS::TempType +Thermostat_impl:: +get_nominal_temp () +{ + short temp; + assert (ICP_get (m_anum, "nominal_temp", &temp, sizeof (temp)) == 0); + 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. + assert ( + ICP_get ( + m_anum, "nominal_temp", &old_temp, sizeof (old_temp) + ) == 0 + ); + + // 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); + } + return old_temp; +} + +// Constructor. + +Thermostat_impl:: +Thermostat_impl (CCS::AssetType anum) : Thermometer_impl (anum) +{ + // Intentionally empty. +} + +// Destructor. + +Thermostat_impl:: +~Thermostat_impl () +{ + // Intentionally empty. +} + +// IDL get_nominal operation. + +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); +} + +//---------------------------------------------------------------- + +// Helper function to add an entry to the asset map. + +void +Controller_impl:: +add_impl (CCS::AssetType anum, Thermometer_impl * tip) +{ + m_assets[anum] = tip; +} + +// Helper function to remove an entry from the asset map. + +void +Controller_impl:: +remove_impl (CCS::AssetType anum) +{ + m_assets.erase (anum); +} + +// Helper function to locate a servant in the asset map. + +bool +Controller_impl:: +exists (CCS::AssetType anum) +{ + return m_assets.find (anum) != m_assets.end (); +} + +// Constructor + +Controller_impl:: +Controller_impl ( + PortableServer::POA_ptr poa, + const char * asset_file +) throw (int) : m_poa (PortableServer::POA::_duplicate (poa)), + m_asset_file (asset_file) +{ + std::ifstream afile (m_asset_file.in (), std::ios::in|std::ios::out);//, 0666); + if (!afile) { + std::cerr << "Cannot open " << m_asset_file.in () << std::endl; + throw 0; + } + CCS::AssetType anum; + while (afile >> anum) + m_assets[anum] = 0; + //afile.close (); + //if (!afile) { + // cerr << "Cannot close " << m_asset_file << endl; + // throw 0; + //} +} + +// Destructor + +Controller_impl:: +~Controller_impl () +{ + // Write out the current set of asset numbers + // and clean up all servant instances. + std::ofstream afile (m_asset_file.in ()); + if (!afile) { + std::cerr << "Cannot open " << m_asset_file.in () << std::endl; + assert (0); + } + AssetMap::iterator i; + for (i = m_assets.begin (); i != m_assets.end (); i++) { + afile << i->first << std::endl; + if (!afile) { + std::cerr << "Cannot update " << m_asset_file.in () << std::endl; + assert (0); + } + delete i->second; + } + //afile.close (); + //if (!afile) { + // cerr << "Cannot close " << m_asset_file << endl; + // assert (0); + //} +} + +CCS::Thermometer_ptr +Controller_impl:: +create_thermometer (CCS::AssetType anum, const char * loc) +throw (CORBA::SystemException, CCS::Controller::DuplicateAsset) +{ + if (anum % 2 == 0) + throw CORBA::BAD_PARAM (); // Thermometers have odd numbers + if (exists (anum)) + throw CCS::Controller::DuplicateAsset (); + + assert (ICP_online (anum) == 0); + assert (ICP_set (anum, "location", loc) == 0); + add_impl (anum, 0); + return make_dref (m_poa.in (), anum); +} + +CCS::Thermostat_ptr +Controller_impl:: +create_thermostat ( + CCS::AssetType anum, + const char* loc, + CCS::TempType temp) +throw ( + CORBA::SystemException, + CCS::Controller::DuplicateAsset, + CCS::Thermostat::BadTemp) +{ + if (anum % 2 != 0) + throw CORBA::BAD_PARAM (); // Thermostats have even numbers + if (exists (anum)) + throw CCS::Controller::DuplicateAsset (); + + assert (ICP_online (anum) == 0); + assert (ICP_set (anum, "location", loc) == 0); + // Set the nominal temperature. + if (ICP_set (anum, "nominal_temp", &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 ( + anum, "MIN_TEMP", + &btd.min_permitted, sizeof (btd.min_permitted) + ); + ICP_get ( + anum, "MAX_TEMP", + &btd.max_permitted, sizeof (btd.max_permitted) + ); + btd.requested = temp; + btd.error_msg = CORBA::string_dup ( + temp > btd.max_permitted ? "Too hot" : "Too cold" + ); + ICP_offline (anum); + throw CCS::Thermostat::BadTemp (btd); + } + + add_impl (anum, 0); + CORBA::Object_var obj = make_dref (m_poa.in (), anum); + return CCS::Thermostat::_narrow (obj.in ()); +} + +// IDL list operation. + +CCS::Controller::ThermometerSeq * +Controller_impl:: +list () throw (CORBA::SystemException) +{ + // Create a new thermometer sequence. Because we know + // the number of elements we will put onto the sequence, + // we use the maximum constructor. + CCS::Controller::ThermometerSeq_var listv + = new CCS::Controller::ThermometerSeq (m_assets.size ()); + listv->length (m_assets.size ()); + + // Loop over the m_assets set and create a + // reference for each device. + CORBA::ULong count = 0; + AssetMap::iterator i; + for (i = m_assets.begin (); i != m_assets.end (); i++) + listv[count++] = make_dref (m_poa.in (), i->first); + return listv._retn (); +} + +// IDL change operation. + +void +Controller_impl:: +change ( + const CCS::Controller::ThermostatSeq & tlist, + CORBA::Short delta +) throw (CORBA::SystemException, CCS::Controller::EChange) +{ + CCS::Controller::EChange ec; // Just in case we need it + + // We cannot add a delta value to a thermostat's temperature + // directly, so for each thermostat, we read the nominal + // temperature, add the delta value to it, and write + // it back again. + for (CORBA::ULong i = 0; i < tlist.length (); i++) { + if (CORBA::is_nil (tlist[i])) + continue; // Skip nil references + + // Read nominal temp and update it. + CCS::TempType tnom = tlist[i]->get_nominal (); + tnom += delta; + try { + tlist[i]->set_nominal (tnom); + } + catch (const CCS::Thermostat::BadTemp &bt) { + // If the update failed because the temperature + // is out of range, we add the thermostat's info + // to the errors sequence. + CORBA::ULong len = ec.errors.length (); + ec.errors.length (len + 1); + ec.errors[len].tmstat_ref = tlist[i].in (); + ec.errors[len].info = bt.details; + } + } + + // If we encountered errors in the above loop, + // we will have added elements to the errors sequence. + if (ec.errors.length () != 0) + throw ec; +} + +// IDL find operation + +void +Controller_impl:: +find (CCS::Controller::SearchSeq & slist) +throw (CORBA::SystemException) +{ + // Loop over input list and lookup each device. + CORBA::ULong listlen = slist.length (); + for (CORBA::ULong i = 0; i < listlen; i++) { + + AssetMap::iterator where; // Iterator for asset set + int num_found = 0; // Num matched per iteration + + // Assume we will not find a matching device. + slist[i].device = CCS::Thermometer::_nil (); + + // Work out whether we are searching by asset, + // model, or location. + CCS::Controller::SearchCriterion sc = slist[i].key._d (); + if (sc == CCS::Controller::ASSET) { + // Search for matching asset number. + where = m_assets.find (slist[i].key.asset_num ()); + if (where != m_assets.end ()) + slist[i].device = make_dref (m_poa.in (), where->first); + } else { + // Search for model or location string. + const char *search_str; + if (sc == CCS::Controller::LOCATION) + search_str = slist[i].key.loc (); + else + search_str = slist[i].key.model_desc (); + + // Find first matching device (if any). + where = find_if ( + m_assets.begin (), m_assets.end (), + StrFinder (sc, search_str) + ); + + // While there are matches... + while (where != m_assets.end ()) { + if (num_found == 0) { + // First match overwrites reference + // in search record. + slist[i].device = make_dref (m_poa.in (), where->first); + } else { + // Further matches each append a new + // element to the search sequence. + CORBA::ULong len = slist.length (); + slist.length (len + 1); + slist[len].key = slist[i].key; + slist[len].device = make_dref (m_poa.in (), where->first); + } + num_found++; + + // Find next matching device with this key. + where = find_if ( + ++where, m_assets.end (), + StrFinder (sc, search_str) + ); + } + } + } +} + +//---------------------------------------------------------------- + +DeviceLocator_impl:: +DeviceLocator_impl (Controller_impl * ctrl) : m_ctrl (ctrl) +{ + // Intentionally empty +} + +PortableServer::Servant +DeviceLocator_impl:: +preinvoke ( + const PortableServer::ObjectId & oid, + PortableServer::POA_ptr /* poa */, + const char * operation, + void * & /* cookie */ +) throw (CORBA::SystemException, PortableServer::ForwardRequest) +{ + // Convert object id into asset number. + CORBA::String_var oid_string; + try { + oid_string = PortableServer::ObjectId_to_string (oid); + } catch (const CORBA::BAD_PARAM &) { + throw CORBA::OBJECT_NOT_EXIST (); + } + + if (strcmp (oid_string.in (), Controller_oid) == 0) + return m_ctrl; + + istrstream istr (oid_string.in ()); + CCS::AssetType anum; + istr >> anum; + if (istr.fail ()) + throw CORBA::OBJECT_NOT_EXIST (); + + // Check whether the device is known. + if (!m_ctrl->exists (anum)) + throw CORBA::OBJECT_NOT_EXIST (); + + // Look at the object map to find out whether + // we have a servant in memory. + Thermometer_impl * servant; + ActiveObjectMap::iterator servant_pos = m_aom.find (anum); + if (servant_pos == m_aom.end ()) { + // No servant in memory. If evictor queue is full, + // evict servant at head of queue. + if (m_eq.size () == MAX_EQ_SIZE) { + servant = m_eq.back (); + m_aom.erase (servant->m_anum); + m_eq.pop_back (); + delete servant; + } + // Instantiate correct type of servant. + char buf[32]; + assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0); + if (strcmp (buf, "Sens-A-Temp") == 0) + servant = new Thermometer_impl (anum); + else + servant = new Thermostat_impl (anum); + } else { + // Servant already in memory. + servant = * (servant_pos->second); // Remember servant + m_eq.erase (servant_pos->second); // Remove from queue + + // If operation is "remove", also remove entry from + // active object map -- the object is about to be deleted. + if (strcmp (operation, "remove") == 0) + m_aom.erase (servant_pos); + } + + // We found a servant, or just instantiated it. + // If the operation is not a remove, move + // the servant to the tail of the evictor queue + // and update its queue position in the map. + if (strcmp (operation, "remove") != 0) { + m_eq.push_front (servant); + m_aom[anum] = m_eq.begin (); + } + + return servant; +} + +//---------------------------------------------------------------- + +int +main (int argc, char * argv[]) +{ + CORBA::ORB_var orb; + + try { + // Initialize orb + orb = CORBA::ORB_init (argc, argv); + + // Get reference to Root POA. + CORBA::Object_var obj + = orb->resolve_initial_references ("RootPOA"); + PortableServer::POA_var poa + = PortableServer::POA::_narrow (obj.in ()); + + // Get POA manager + PortableServer::POAManager_var poa_mgr = poa->the_POAManager (); + + // Create a policy list. We use persistent objects with + // user-assigned IDs, and explicit activation. + CORBA::PolicyList policy_list; + policy_list.length (6); + policy_list[0] = poa->create_lifespan_policy ( + PortableServer::TRANSIENT // REVISIT + ); + policy_list[1] = poa->create_id_assignment_policy ( + PortableServer::USER_ID + ); + policy_list[2] = poa->create_implicit_activation_policy ( + PortableServer::NO_IMPLICIT_ACTIVATION + ); + policy_list[3] = poa->create_request_processing_policy ( + PortableServer::USE_SERVANT_MANAGER + ); + policy_list[4] = poa->create_servant_retention_policy ( + PortableServer::NON_RETAIN + ); + policy_list[5] = poa->create_thread_policy ( + PortableServer::SINGLE_THREAD_MODEL + ); + + // Create a POA for all CCS elements. + PortableServer::POA_var ccs_poa + = poa->create_POA ("CCS_POA", poa_mgr.in (), policy_list); + + // Create a controller and set static m_ctrl member + // for thermostats and thermometers. + Controller_impl ctrl_servant (ccs_poa.in (), "/tmp/CCS_assets"); + Thermometer_impl::m_ctrl = &ctrl_servant; + + // Create a reference for the controller and + // create the corresponding CORBA object. + PortableServer::ObjectId_var oid + = PortableServer::string_to_ObjectId (Controller_oid); + CORBA::Object_var ctrl + = ccs_poa->create_reference_with_id ( + oid.in (), "IDL:acme.com/CCS/Controller:1.0" + ); + + // Get reference to initial naming context. + CosNaming::NamingContext_var inc + = resolve_init<CosNaming::NamingContext> ( + orb.in (), "NameService" + ); + + // Attempt to create CCS context. + CosNaming::Name n; + n.length (1); + n[0].id = CORBA::string_dup ("CCS"); + try { + CosNaming::NamingContext_var nc + = inc->bind_new_context (n); + } catch (const CosNaming::NamingContext::AlreadyBound &) { + // Fine, CCS context already exists. + } + + // Force binding of controller reference to make + // sure it is always up-to-date. + n.length (2); + n[1].id = CORBA::string_dup ("Controller"); + inc->rebind (n, ctrl.in ()); + + // Instantiate the servant locator for devices. + PortableServer::ServantManager_var locator = + new DeviceLocator_impl (&ctrl_servant); + + // Set servant locator. + ccs_poa->set_servant_manager (locator.in ()); + + // Activate the POA manager. + poa_mgr->activate (); + + // Accept requests + orb->run (); + } + catch (const CORBA::Exception & e) { + std::cerr << "Uncaught CORBA exception: " + //<< e + << std::endl; + return 1; + } + catch (...) { + assert (0); // Uncaught exception, dump core + } + return 0; +} |