Merge pull request #1844 from jrw972/monterey
[ACE_TAO.git] / TAO / examples / Advanced / ch_21 / server.cpp
blob4ffc422b94a6a48aefcde5e3c73ae5a8ba50a8f0
2 //=============================================================================
3 /**
4 * @file server.cpp
6 * @author Source code used in TAO has been modified and adapted from the codeprovided in the book
7 * @author "Advanced CORBA Programming with C++" by MichiHenning and Steve Vinoski. Copyright 1999. Addison-Wesley
8 * @author Reading
9 * @author MA.Modified for TAO by Mike Moran <mm4@cs.wustl.edu>
11 //=============================================================================
14 #include <ace/streams.h>
15 #include <strstream>
16 #include "server.h"
17 #include <algorithm>
18 #include "icp.h"
20 using namespace std;
22 const char* Controller_oid = "Controller";
23 const unsigned int DeviceLocator_impl::MAX_EQ_SIZE = 100;
24 //----------------------------------------------------------------
26 // Generic ostream inserter for exceptions. Inserts the exception
27 // name, if available, and the repository ID otherwise.
29 #if 0 // This inserter is not needed for TAO.
31 static ostream &
32 operator<< (ostream & os, const CORBA::Exception & e)
34 CORBA::Any tmp;
35 tmp <<= e;
37 CORBA::TypeCode_var tc = tmp.type ();
38 const char * p = tc->name ();
39 if (*p != '\0')
40 os << p;
41 else
42 os << tc->id ();
43 return os;
46 #endif
48 //----------------------------------------------------------------
50 // Helper function to create object references.
52 static CCS::Thermometer_ptr make_dref (PortableServer::POA_ptr poa, CCS::AssetType anum)
54 // Convert asset number to OID.
55 ostrstream ostr;
56 ostr << anum << ends;
57 char * anum_str = ostr.str ();
58 PortableServer::ObjectId_var oid
59 = PortableServer::string_to_ObjectId (anum_str);
60 delete[] anum_str;
62 // Look at the model via the network to determine
63 // the repository ID.
64 char buf[32];
65 assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0);
66 const char * rep_id = ACE_OS::strcmp (buf, "Sens-A-Temp") == 0
67 ? "IDL:acme.com/CCS/Thermometer:1.0"
68 : "IDL:acme.com/CCS/Thermostat:1.0";
70 // Make a new reference.
71 CORBA::Object_var obj
72 = poa->create_reference_with_id (oid.in (), rep_id);
73 return CCS::Thermometer::_narrow (obj.in ());
76 //----------------------------------------------------------------
78 Controller_impl * Thermometer_impl::m_ctrl; // static member
80 // Helper function to read the model string from a device.
82 CCS::ModelType
83 Thermometer_impl::
84 get_model ()
86 char buf[32];
87 assert (ICP_get (m_anum, "model", buf, sizeof (buf)) == 0);
88 return CORBA::string_dup (buf);
91 // Helper function to read the temperature from a device.
93 CCS::TempType
94 Thermometer_impl::
95 get_temp ()
97 short temp;
98 assert (ICP_get (m_anum, "temperature", &temp, sizeof (temp)) == 0);
99 return temp;
102 // Helper function to read the location from a device.
104 CCS::LocType
105 Thermometer_impl::
106 get_loc ()
108 char buf[32];
109 assert (ICP_get (m_anum, "location", buf, sizeof (buf)) == 0);
110 return CORBA::string_dup (buf);
113 // Helper function to set the location of a device.
115 void
116 Thermometer_impl::
117 set_loc (const char * loc)
119 assert (ICP_set (m_anum, "location", loc) == 0);
122 // Constructor.
124 Thermometer_impl::
125 Thermometer_impl (CCS::AssetType anum) :
126 m_anum (anum), m_ref_count (1), m_removed (false)
128 m_ctrl->add_impl (anum); // Add self to controller's set
131 // Destructor.
133 Thermometer_impl::
134 ~Thermometer_impl ()
136 if (m_removed)
137 assert (ICP_offline (m_anum) == 0);
140 void
141 Thermometer_impl::_add_ref ()
143 ACE_GUARD (ACE_Mutex, ace_mon, m_count_mutex);
144 ++m_ref_count++;
147 void
148 Thermometer_impl::_remove_ref ()
150 bool del = false;
152 ACE_GUARD (ACE_Mutex, ace_mon, m_count_mutex);
153 if (--m_ref_count == 0)
154 del = true;
156 if (del)
157 delete this;
160 // IDL model attribute.
162 CCS::ModelType
163 Thermometer_impl::model ()
165 return get_model ();
168 // IDL asset_num attribute.
170 CCS::AssetType
171 Thermometer_impl::asset_num ()
173 return m_anum;
176 // IDL temperature attribute.
178 CCS::TempType
179 Thermometer_impl::temperature ()
181 return get_temp ();
184 // IDL location attribute accessor.
186 CCS::LocType
187 Thermometer_impl::location ()
189 return get_loc ();
192 // IDL remove operation.
194 void
195 Thermometer_impl::remove ()
197 m_removed = true;
198 _remove_ref ();
201 // IDL location attribute modifier.
203 void
204 Thermometer_impl::location (const char *loc)
206 set_loc (loc);
209 //----------------------------------------------------------------
211 // Helper function to get a thermostat's nominal temperature.
213 CCS::TempType
214 Thermostat_impl::
215 get_nominal_temp ()
217 short temp;
218 assert (ICP_get (m_anum, "nominal_temp", &temp, sizeof (temp)) == 0);
219 return temp;
222 // Helper function to set a thermostat's nominal temperature.
224 CCS::TempType
225 Thermostat_impl::set_nominal_temp (CCS::TempType new_temp)
227 short old_temp;
229 // We need to return the previous nominal temperature,
230 // so we first read the current nominal temperature before
231 // changing it.
232 assert (
233 ICP_get (
234 m_anum, "nominal_temp", &old_temp, sizeof (old_temp)
235 ) == 0
238 // Now set the nominal temperature to the new value.
239 if (ICP_set (m_anum, "nominal_temp", &new_temp) != 0) {
241 // If ICP_set () failed, read this thermostat's minimum
242 // and maximum so we can initialize the BadTemp exception.
243 CCS::Thermostat::BtData btd;
244 ICP_get (
245 m_anum, "MIN_TEMP",
246 &btd.min_permitted, sizeof (btd.min_permitted)
248 ICP_get (
249 m_anum, "MAX_TEMP",
250 &btd.max_permitted, sizeof (btd.max_permitted)
252 btd.requested = new_temp;
253 btd.error_msg = CORBA::string_dup (
254 new_temp > btd.max_permitted ? "Too hot" : "Too cold"
256 throw CCS::Thermostat::BadTemp (btd);
258 return old_temp;
261 // Constructor.
263 Thermostat_impl::
264 Thermostat_impl (CCS::AssetType anum) : Thermometer_impl (anum)
266 // Intentionally empty.
269 // Destructor.
271 Thermostat_impl::
272 ~Thermostat_impl ()
274 // Intentionally empty.
277 // IDL get_nominal operation.
279 CCS::TempType
280 Thermostat_impl::get_nominal ()
282 return get_nominal_temp ();
285 // IDL set_nominal operation.
287 CCS::TempType
288 Thermostat_impl::set_nominal (CCS::TempType new_temp)
290 return set_nominal_temp (new_temp);
293 //----------------------------------------------------------------
295 // Helper function to add an entry to the asset map.
297 void
298 Controller_impl::
299 add_impl (CCS::AssetType anum)
301 m_assets.insert (anum);
304 // Helper function to remove an entry from the asset map.
306 void
307 Controller_impl::
308 remove_impl (CCS::AssetType anum)
310 m_assets.erase (anum);
313 // Helper function to locate a servant in the asset map.
315 bool
316 Controller_impl::exists (CCS::AssetType anum)
318 return m_assets.find (anum) != m_assets.end ();
321 // Constructor
323 Controller_impl::
324 Controller_impl (PortableServer::POA_ptr poa, const char * asset_file)
325 : m_poa (PortableServer::POA::_duplicate (poa)),
326 m_asset_file (asset_file)
328 std::ifstream afile (m_asset_file.in (), std::ios::in|std::ios::out);//, 0666);
329 if (!afile) {
330 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
331 throw 0;
333 CCS::AssetType anum;
334 while (afile >> anum)
335 m_assets.insert (anum);
336 // afile.close ();
337 // if (!afile) {
338 // cerr << "Cannot close " << m_asset_file.in () << endl;
339 // throw 0;
340 // }
343 // Destructor
345 Controller_impl::
346 ~Controller_impl ()
348 // Write out the current set of asset numbers
349 // and clean up all servant instances.
350 std::ofstream afile (m_asset_file.in ());
351 if (!afile) {
352 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
353 assert (0);
355 AssetSet::iterator i;
356 for (i = m_assets.begin (); i != m_assets.end (); i++) {
357 afile << *i << std::endl;
358 if (!afile) {
359 std::cerr << "Cannot update " << m_asset_file.in () << std::endl;
360 assert (0);
363 // afile.close ();
364 // if (!afile) {
365 // cerr << "Cannot close " << m_asset_file.in () << endl;
366 // assert (0);
367 // }
370 CCS::Thermometer_ptr
371 Controller_impl::create_thermometer (CCS::AssetType anum, const char * loc)
374 ACE_GUARD (ACE_Mutex, ace_mon, m_assets_mutex);
376 if (anum % 2 == 0)
377 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
378 if (exists (anum))
379 throw CCS::Controller::DuplicateAsset ();
381 assert (ICP_online (anum) == 0);
382 assert (ICP_set (anum, "location", loc) == 0);
383 add_impl (anum);
386 return make_dref (m_poa.in (), anum);
389 CCS::Thermostat_ptr
390 Controller_impl::
391 create_thermostat (
392 CCS::AssetType anum,
393 const char* loc,
394 CCS::TempType temp)
397 ACE_GUARD (ACE_Mutex, ace_mon, m_assets_mutex);
400 if (anum % 2 != 0)
401 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
402 if (exists (anum))
403 throw CCS::Controller::DuplicateAsset ();
405 assert (ICP_online (anum) == 0);
406 assert (ICP_set (anum, "location", loc) == 0);
407 // Set the nominal temperature.
408 if (ICP_set (anum, "nominal_temp", &temp) != 0) {
410 // If ICP_set () failed, read this thermostat's minimum
411 // and maximum so we can initialize the BadTemp exception.
412 CCS::Thermostat::BtData btd;
413 ICP_get (
414 anum, "MIN_TEMP",
415 &btd.min_permitted, sizeof (btd.min_permitted)
417 ICP_get (
418 anum, "MAX_TEMP",
419 &btd.max_permitted, sizeof (btd.max_permitted)
421 btd.requested = temp;
422 btd.error_msg = CORBA::string_dup (
423 temp > btd.max_permitted ? "Too hot" : "Too cold"
425 throw CCS::Thermostat::BadTemp (btd);
428 add_impl (anum);
431 CORBA::Object_var obj = make_dref (m_poa.in (), anum);
432 return CCS::Thermostat::_narrow (obj.in ());
435 // IDL list operation.
437 CCS::Controller::ThermometerSeq *
438 Controller_impl::list ()
440 // Create a new thermometer sequence. Because we know
441 // the number of elements we will put onto the sequence,
442 // we use the maximum constructor.
443 CCS::Controller::ThermometerSeq_var listv
444 = new CCS::Controller::ThermometerSeq (m_assets.size ());
445 listv->length (m_assets.size ());
447 AssetSet tmp_assets;
449 ACE_GUARD (ACE_Mutex, ace_mon, m_assets_mutex);
450 tmp_assets = m_assets;
453 // Loop over the m_assets set and create a
454 // reference for each device.
455 CORBA::ULong count = 0;
456 AssetSet::iterator i;
457 for (i = tmp_assets.begin (); i != tmp_assets.end (); i++)
458 listv[count++] = make_dref (m_poa.in (), *i);
459 return listv._retn ();
462 // IDL change operation.
464 void
465 Controller_impl::
466 change (
467 const CCS::Controller::ThermostatSeq & tlist,
468 CORBA::Short delta
471 CCS::Controller::EChange ec; // Just in case we need it
473 // We cannot add a delta value to a thermostat's temperature
474 // directly, so for each thermostat, we read the nominal
475 // temperature, add the delta value to it, and write
476 // it back again.
477 for (CORBA::ULong i = 0; i < tlist.length (); i++) {
478 if (CORBA::is_nil (tlist[i]))
479 continue; // Skip nil references
481 // Read nominal temp and update it.
482 CCS::TempType tnom = tlist[i]->get_nominal ();
483 tnom += delta;
484 try {
485 tlist[i]->set_nominal (tnom);
487 catch (const CCS::Thermostat::BadTemp &bt) {
488 // If the update failed because the temperature
489 // is out of range, we add the thermostat's info
490 // to the errors sequence.
491 CORBA::ULong len = ec.errors.length ();
492 ec.errors.length (len + 1);
493 ec.errors[len].tmstat_ref = tlist[i].in ();
494 ec.errors[len].info = bt.details;
498 // If we encountered errors in the above loop,
499 // we will have added elements to the errors sequence.
500 if (ec.errors.length () != 0)
501 throw ec;
504 // IDL find operation
506 void
507 Controller_impl::
508 find (CCS::Controller::SearchSeq & slist)
510 // Loop over input list and lookup each device.
511 CORBA::ULong listlen = slist.length ();
512 for (CORBA::ULong i = 0; i < listlen; i++) {
514 AssetSet::iterator where; // Iterator for asset set
515 int num_found = 0; // Num matched per iteration
517 // Assume we will not find a matching device.
518 slist[i].device = CCS::Thermometer::_nil ();
520 // Work out whether we are searching by asset,
521 // model, or location.
522 CCS::Controller::SearchCriterion sc = slist[i].key._d ();
523 if (sc == CCS::Controller::ASSET) {
524 // Search for matching asset number.
525 bool make = false;
526 CCS::AssetType num = 0;
528 ACE_GUARD (ACE_Mutex, ace_mon, m_assets_mutex);
529 where = m_assets.find (slist[i].key.asset_num ());
530 if (where != m_assets.end ()) {
531 num = *where;
532 make = true;
535 if (make)
536 slist[i].device = make_dref (m_poa.in (), num);
537 } else {
538 // Search for model or location string.
539 const char *search_str;
540 if (sc == CCS::Controller::LOCATION)
541 search_str = slist[i].key.loc ();
542 else
543 search_str = slist[i].key.model_desc ();
545 // Find first matching device (if any).
546 where = find_if (
547 m_assets.begin (), m_assets.end (),
548 StrFinder (sc, search_str)
551 // While there are matches...
552 while (where != m_assets.end ()) {
553 if (num_found == 0) {
554 // First match overwrites reference
555 // in search record.
556 slist[i].device = make_dref (m_poa.in (), *where);
557 } else {
558 // Further matches each append a new
559 // element to the search sequence.
560 CORBA::ULong len = slist.length ();
561 slist.length (len + 1);
562 slist[len].key = slist[i].key;
563 slist[len].device = make_dref (m_poa.in (), *where);
565 num_found++;
567 // Find next matching device with this key.
568 where = find_if (
569 ++where, m_assets.end (),
570 StrFinder (sc, search_str)
577 //----------------------------------------------------------------
579 DeviceLocator_impl::
580 DeviceLocator_impl (Controller_impl * ctrl) : m_ctrl (ctrl)
582 // Intentionally empty
585 PortableServer::Servant
586 DeviceLocator_impl::
587 preinvoke (
588 const PortableServer::ObjectId & oid,
589 PortableServer::POA_ptr /* poa */ ,
590 const char * operation,
591 void * & /* cookie */
594 // Convert object id into asset number.
595 CORBA::String_var oid_string;
596 try {
597 oid_string = PortableServer::ObjectId_to_string (oid);
598 } catch (const CORBA::BAD_PARAM &) {
599 throw CORBA::OBJECT_NOT_EXIST ();
602 istrstream istr (oid_string.in ());
603 CCS::AssetType anum;
604 istr >> anum;
605 if (istr.fail ())
606 throw CORBA::OBJECT_NOT_EXIST ();
608 ACE_GUARD (ACE_Mutex, ace_mon, m_ctrl->m_assets_mutex);
610 // Check whether the device is known.
611 if (!m_ctrl->exists (anum))
612 throw CORBA::OBJECT_NOT_EXIST ();
614 // Look at the object map to find out whether
615 // we have a servant in memory.
616 Thermometer_impl * servant;
617 ActiveObjectMap::iterator servant_pos = m_aom.find (anum);
618 if (servant_pos == m_aom.end ()) {
619 // No servant in memory. If evictor queue is full,
620 // evict servant at head of queue.
621 if (m_eq.size () == MAX_EQ_SIZE) {
622 servant = m_eq.back ();
623 m_aom.erase (servant->m_anum);
624 m_eq.pop_back ();
625 servant->_remove_ref ();
627 // Instantiate correct type of servant.
628 char buf[32];
629 assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0);
630 if (ACE_OS::strcmp (buf, "Sens-A-Temp") == 0)
631 servant = new Thermometer_impl (anum);
632 else
633 servant = new Thermostat_impl (anum);
634 } else {
635 // Servant already in memory.
636 servant = * (servant_pos->second); // Remember servant
637 m_eq.erase (servant_pos->second); // Remove from queue
639 // If operation is "remove", also remove entry from
640 // active object map -- the object is about to be deleted.
641 if (ACE_OS::strcmp (operation, "remove") == 0)
642 m_aom.erase (servant_pos);
645 // We found a servant, or just instantiated it.
646 // If the operation is not a remove, move
647 // the servant to the tail of the evictor queue
648 // and update its queue position in the map.
649 if (ACE_OS::strcmp (operation, "remove") != 0) {
650 m_eq.push_front (servant);
651 m_aom[anum] = m_eq.begin ();
652 } else {
653 m_ctrl->remove_impl (anum);
656 return servant;
659 //----------------------------------------------------------------
662 ACE_TMAIN(int argc, ACE_TCHAR *argv[])
664 try {
665 // Initialize orb
666 CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);
668 // Get reference to Root POA.
669 CORBA::Object_var obj
670 = orb->resolve_initial_references ("RootPOA");
671 PortableServer::POA_var poa
672 = PortableServer::POA::_narrow (obj.in ());
674 // Get POA manager
675 PortableServer::POAManager_var poa_mgr = poa->the_POAManager ();
677 // Create a policy list. We use persistent objects with
678 // user-assigned IDs, and explicit activation.
679 CORBA::PolicyList policy_list;
680 policy_list.length (3);
681 policy_list[0] = poa->create_lifespan_policy (
682 PortableServer::TRANSIENT // REVISIT
684 policy_list[1] = poa->create_id_assignment_policy (
685 PortableServer::USER_ID
687 policy_list[2] = poa->create_implicit_activation_policy (
688 PortableServer::NO_IMPLICIT_ACTIVATION
691 // Create a POA for the controller.
692 PortableServer::POA_var ctrl_poa
693 = poa->create_POA ("CtrlPOA", poa_mgr.in (), policy_list);
695 policy_list.length (5);
696 policy_list[3] = poa->create_request_processing_policy (
697 PortableServer::USE_SERVANT_MANAGER
699 policy_list[4] = poa->create_servant_retention_policy (
700 PortableServer::NON_RETAIN
703 // Create a POA for the devices.
704 PortableServer::POA_var dev_poa
705 = ctrl_poa->create_POA ("DevPOA", poa_mgr.in (), policy_list);
707 // Create a controller and set static m_ctrl member
708 // for thermostats and thermometers.
709 Controller_impl ctrl_servant (dev_poa.in (), "/tmp/CCS_assets");
710 Thermometer_impl::m_ctrl = &ctrl_servant;
712 obj = ctrl_servant._this ();
714 // Write a reference for the controller to stdout.
715 CORBA::String_var str = orb->object_to_string (obj.in ());
716 std::cout << str.in () << std::endl << std::endl;
718 // Instantiate the servant locator for devices.
719 PortableServer::ServantManager_var locator =
720 new DeviceLocator_impl (&ctrl_servant);
722 // Set servant locator.
723 dev_poa->set_servant_manager (locator.in ());
725 // Activate the POA manager.
726 poa_mgr->activate ();
728 // Accept requests
729 orb->run ();
731 catch (const CORBA::Exception & e) {
732 std::cerr << "Uncaught CORBA exception: "
733 << e
734 << std::endl;
735 return 1;
737 catch (...) {
738 assert (0); // Uncaught exception, dump core
740 return 0;