summaryrefslogtreecommitdiff
path: root/TAO/examples/Advanced/ch_18/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TAO/examples/Advanced/ch_18/server.cpp')
-rw-r--r--TAO/examples/Advanced/ch_18/server.cpp791
1 files changed, 791 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..8cf4fac044a
--- /dev/null
+++ b/TAO/examples/Advanced/ch_18/server.cpp
@@ -0,0 +1,791 @@
+// $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.
+//
+// Modified for TAO by Mike Moran <mm4@cs.wustl.edu>
+//
+// ============================================================================
+
+
+
+
+#include "server.h"
+#include <algorithm>
+#include "icp.h"
+#include <orbsvcs/CosNamingC.h>
+#include <strstream.h>
+
+// #include <iostream.h>
+// #include <fstream.h>
+
+const char * Controller_oid = "Controller";
+
+//----------------------------------------------------------------
+
+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 & e) {
+ throw;
+ }
+ catch (const CORBA::Exception & e) {
+ cerr << "Cannot get initial reference for "
+ << id << ": " << e << 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) {
+ cerr << "Cannot narrow reference for "
+ << id << ": " << e << endl;
+ throw 0;
+ }
+ if (CORBA::is_nil(ref.in())) {
+ cerr << "Incorrect type of reference for "
+ << id << 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 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
+
+//----------------------------------------------------------------
+
+// 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)
+{
+ fstream afile(m_asset_file.in(), ios::in|ios::out, 0666);
+ if (!afile) {
+ cerr << "Cannot open " << m_asset_file.in() << 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.
+ ofstream afile(m_asset_file.in());
+ if (!afile) {
+ cerr << "Cannot open " << m_asset_file.in() << endl;
+ assert(0);
+ }
+ AssetMap::iterator i;
+ for (i = m_assets.begin(); i != m_assets.end(); i++) {
+ afile << i->first << endl;
+ if (!afile) {
+ cerr << "Cannot update " << m_asset_file.in() << 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];
+ 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 */,
+ CORBA_Environment &
+) 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.
+ DeviceLocator_impl my_locator(&ctrl_servant);
+ PortableServer::ServantManager_var locator
+ = my_locator._this();
+
+ // 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) {
+ cerr << "Uncaught CORBA exception: " << e << endl;
+ return 1;
+ }
+ catch (...) {
+ assert(0); // Uncaught exception, dump core
+ }
+ return 0;
+}