summaryrefslogtreecommitdiff
path: root/ACE/TAO/examples/Advanced/ch_21/server.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/TAO/examples/Advanced/ch_21/server.cpp')
-rw-r--r--ACE/TAO/examples/Advanced/ch_21/server.cpp748
1 files changed, 748 insertions, 0 deletions
diff --git a/ACE/TAO/examples/Advanced/ch_21/server.cpp b/ACE/TAO/examples/Advanced/ch_21/server.cpp
new file mode 100644
index 00000000000..93ab672566a
--- /dev/null
+++ b/ACE/TAO/examples/Advanced/ch_21/server.cpp
@@ -0,0 +1,748 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// TAO/examples/Advanced/ch_21
+//
+// = 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 <ace/streams.h>
+#include <strstream>
+#include "server.h"
+#include <ace/Synch_T.h>
+#include <algorithm>
+#include "icp.h"
+
+using namespace std;
+
+const char* Controller_oid = "Controller";
+const unsigned int DeviceLocator_impl::MAX_EQ_SIZE = 100;
+//----------------------------------------------------------------
+
+// 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 = ACE_OS::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_ref_count (1), m_removed (false)
+{
+ m_ctrl->add_impl (anum); // Add self to controller's set
+}
+
+// Destructor.
+
+Thermometer_impl::
+~Thermometer_impl ()
+{
+ if (m_removed)
+ assert (ICP_offline (m_anum) == 0);
+}
+
+void
+Thermometer_impl::_add_ref ()
+{
+ ACE_Guard<ACE_Mutex> guard (m_count_mutex);
+ m_ref_count++;
+}
+
+void
+Thermometer_impl::_remove_ref ()
+{
+ bool del = false;
+ {
+ ACE_Guard<ACE_Mutex> guard (m_count_mutex);
+ if (--m_ref_count == 0)
+ del = true;
+ }
+ if (del)
+ delete this;
+}
+
+// IDL model attribute.
+
+CCS::ModelType
+Thermometer_impl::model ()
+{
+ return get_model ();
+}
+
+// IDL asset_num attribute.
+
+CCS::AssetType
+Thermometer_impl::asset_num ()
+{
+ return m_anum;
+}
+
+// IDL temperature attribute.
+
+CCS::TempType
+Thermometer_impl::temperature ()
+{
+ return get_temp ();
+}
+
+// IDL location attribute accessor.
+
+CCS::LocType
+Thermometer_impl::location ()
+{
+ return get_loc ();
+}
+
+// IDL remove operation.
+
+void
+Thermometer_impl::remove ()
+{
+ m_removed = true;
+ _remove_ref ();
+}
+
+// IDL location attribute modifier.
+
+void
+Thermometer_impl::location (const char *loc)
+{
+ 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)
+{
+ 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 ()
+{
+ return get_nominal_temp ();
+}
+
+// IDL set_nominal operation.
+
+CCS::TempType
+Thermostat_impl::set_nominal (CCS::TempType new_temp)
+{
+ return set_nominal_temp (new_temp);
+}
+
+//----------------------------------------------------------------
+
+// Helper function to add an entry to the asset map.
+
+void
+Controller_impl::
+add_impl (CCS::AssetType anum)
+{
+ m_assets.insert (anum);
+}
+
+// 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)
+ : 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.insert (anum);
+ // afile.close ();
+ // if (!afile) {
+ // cerr << "Cannot close " << m_asset_file.in () << 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);
+ }
+ AssetSet::iterator i;
+ for (i = m_assets.begin (); i != m_assets.end (); i++) {
+ afile << *i << std::endl;
+ if (!afile) {
+ std::cerr << "Cannot update " << m_asset_file.in () << std::endl;
+ assert (0);
+ }
+ }
+ // afile.close ();
+ // if (!afile) {
+ // cerr << "Cannot close " << m_asset_file.in () << endl;
+ // assert (0);
+ // }
+}
+
+CCS::Thermometer_ptr
+Controller_impl::create_thermometer (CCS::AssetType anum, const char * loc)
+{
+ {
+ ACE_Guard<ACE_Mutex> guard (m_assets_mutex);
+
+ 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);
+ }
+
+ return make_dref (m_poa.in (), anum);
+}
+
+CCS::Thermostat_ptr
+Controller_impl::
+create_thermostat (
+ CCS::AssetType anum,
+ const char* loc,
+ CCS::TempType temp)
+{
+ {
+ ACE_Guard<ACE_Mutex> guard (m_assets_mutex);
+
+ 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"
+ );
+ throw CCS::Thermostat::BadTemp (btd);
+ }
+
+ add_impl (anum);
+ }
+
+ 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 ()
+{
+ // 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 ());
+
+ AssetSet tmp_assets;
+ {
+ ACE_Guard<ACE_Mutex> guard (m_assets_mutex);
+ tmp_assets = m_assets;
+ }
+
+ // Loop over the m_assets set and create a
+ // reference for each device.
+ CORBA::ULong count = 0;
+ AssetSet::iterator i;
+ for (i = tmp_assets.begin (); i != tmp_assets.end (); i++)
+ listv[count++] = make_dref (m_poa.in (), *i);
+ return listv._retn ();
+}
+
+// IDL change operation.
+
+void
+Controller_impl::
+change (
+ const CCS::Controller::ThermostatSeq & tlist,
+ CORBA::Short delta
+)
+{
+ 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)
+{
+ // Loop over input list and lookup each device.
+ CORBA::ULong listlen = slist.length ();
+ for (CORBA::ULong i = 0; i < listlen; i++) {
+
+ AssetSet::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.
+ bool make = false;
+ CCS::AssetType num = 0;
+ {
+ ACE_Guard<ACE_Mutex> guard (m_assets_mutex);
+ where = m_assets.find (slist[i].key.asset_num ());
+ if (where != m_assets.end ()) {
+ num = *where;
+ make = true;
+ }
+ }
+ if (make)
+ slist[i].device = make_dref (m_poa.in (), num);
+ } 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);
+ } 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);
+ }
+ 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 */
+)
+{
+ // 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 ();
+ }
+
+ istrstream istr (oid_string.in ());
+ CCS::AssetType anum;
+ istr >> anum;
+ if (istr.fail ())
+ throw CORBA::OBJECT_NOT_EXIST ();
+
+ ACE_Guard<ACE_Mutex> guard (m_ctrl->m_assets_mutex);
+
+ // 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 ();
+ servant->_remove_ref ();
+ }
+ // Instantiate correct type of servant.
+ char buf[32];
+ assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0);
+ if (ACE_OS::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 (ACE_OS::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 (ACE_OS::strcmp (operation, "remove") != 0) {
+ m_eq.push_front (servant);
+ m_aom[anum] = m_eq.begin ();
+ } else {
+ m_ctrl->remove_impl (anum);
+ }
+
+ return servant;
+}
+
+//----------------------------------------------------------------
+
+int
+ACE_TMAIN(int argc, ACE_TCHAR *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 ());
+
+ // 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 (3);
+ 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
+ );
+
+ // Create a POA for the controller.
+ PortableServer::POA_var ctrl_poa
+ = poa->create_POA ("CtrlPOA", poa_mgr.in (), policy_list);
+
+ policy_list.length (5);
+ policy_list[3] = poa->create_request_processing_policy (
+ PortableServer::USE_SERVANT_MANAGER
+ );
+ policy_list[4] = poa->create_servant_retention_policy (
+ PortableServer::NON_RETAIN
+ );
+
+ // Create a POA for the devices.
+ PortableServer::POA_var dev_poa
+ = ctrl_poa->create_POA ("DevPOA", poa_mgr.in (), policy_list);
+
+ // Create a controller and set static m_ctrl member
+ // for thermostats and thermometers.
+ Controller_impl ctrl_servant (dev_poa.in (), "/tmp/CCS_assets");
+ Thermometer_impl::m_ctrl = &ctrl_servant;
+
+ obj = ctrl_servant._this ();
+
+ // Write a reference for the controller to stdout.
+ CORBA::String_var str = orb->object_to_string (obj.in ());
+ std::cout << str.in () << std::endl << std::endl;
+
+ // Instantiate the servant locator for devices.
+ PortableServer::ServantManager_var locator =
+ new DeviceLocator_impl (&ctrl_servant);
+
+ // Set servant locator.
+ dev_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;
+}