// $Id$ // ============================================================================ // // = LIBRARY // TAO/examples/Advanced/ch_8_and_10 // // = 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. // // Modified for TAO by Mike Moran // // ============================================================================ #include "server.h" #include #include "icp.h" //#include //#include //---------------------------------------------------------------- // Generic ostream inserter for exceptions. Inserts the exception // name, if available, and the repository ID otherwise. #if 0 //This inserter may or may not be needed for your ORB. 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 //---------------------------------------------------------------- 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) { long result = 0; result = ICP_set(m_anum, "location", loc); assert (result == 0); } // Constructor. Thermometer_impl:: Thermometer_impl( CCS::AssetType anum, const char * location ) : m_anum(anum) { assert(ICP_online(anum) == 0); // Mark device as on-line set_loc(location); m_ctrl->add_impl(anum, this); // Add self to controller's 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 (...) { assert(0); // Prevent exceptions from escaping } } // 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); } //---------------------------------------------------------------- // 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, 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); } // 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 for thermometers and thermostats to // add themselves to the m_assets map. void Controller_impl:: add_impl(CCS::AssetType anum, Thermometer_impl * tip) { m_assets[anum] = tip; } // Helper function for thermometers and thermostats to // remove themselves from the m_assets map. void Controller_impl:: remove_impl(CCS::AssetType anum) { m_assets.erase(anum); } // 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 map 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++] = i->second->_this(); 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 look up each device. CORBA::ULong listlen = slist.length(); for (CORBA::ULong i = 0; i < listlen; i++) { AssetMap::iterator where; // Iterator for asset map 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 = where->second->_this(); } 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 = std::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 = where->second->_this(); } else { // Each further match appends 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 = where->second->_this(); } num_found++; // Find next matching device with this key. where = std::find_if( ++where, m_assets.end(), StrFinder(sc, search_str) ); } } } std::cerr << "end" << std::endl; } //---------------------------------------------------------------- int main(int argc, char * argv[]) { try { // Initialize orb CORBA::ORB_var 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()); // Activate POA manager PortableServer::POAManager_var mgr = poa->the_POAManager(); mgr->activate(); // Create a controller and set static m_ctrl member // for thermostats and thermometers. Controller_impl ctrl_servant; Thermometer_impl::m_ctrl = &ctrl_servant; // Write controller stringified reference to stdout CCS::Controller_var ctrl = ctrl_servant._this(); CORBA::String_var str = orb->object_to_string(ctrl.in()); std::cout << str.in() << std::endl << std::endl; // Create a few devices. (Thermometers have odd asset // numbers, thermostats have even asset numbers.) Thermometer_impl thermo1(2029, "Deep Thought"); Thermometer_impl thermo2(8053, "HAL"); Thermometer_impl thermo3(1027, "ENIAC"); Thermostat_impl tmstat1(3032, "Colossus", 68); Thermostat_impl tmstat2(4026, "ENIAC", 60); Thermostat_impl tmstat3(4088, "ENIAC", 50); Thermostat_impl tmstat4(8042, "HAL", 40); // Accept requests orb->run(); } catch (const CORBA::Exception & e) { std::cerr << "Uncaught CORBA exception: " //<< e << std::endl; return 1; } catch (...) { assert(0); // Unexpected exception, dump core } return 0; }