Changes to attempt to silence bcc64x
[ACE_TAO.git] / TAO / examples / Advanced / ch_21 / server.cpp
blob2c7b2208f841eddccc8ccd099745c3df60618527
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) {
240 // If ICP_set () failed, read this thermostat's minimum
241 // and maximum so we can initialize the BadTemp exception.
242 CCS::Thermostat::BtData btd;
243 ICP_get (
244 m_anum, "MIN_TEMP",
245 &btd.min_permitted, sizeof (btd.min_permitted)
247 ICP_get (
248 m_anum, "MAX_TEMP",
249 &btd.max_permitted, sizeof (btd.max_permitted)
251 btd.requested = new_temp;
252 btd.error_msg = CORBA::string_dup (
253 new_temp > btd.max_permitted ? "Too hot" : "Too cold"
255 throw CCS::Thermostat::BadTemp (btd);
257 return old_temp;
260 // Constructor.
262 Thermostat_impl::
263 Thermostat_impl (CCS::AssetType anum) : Thermometer_impl (anum)
265 // Intentionally empty.
268 // Destructor.
270 Thermostat_impl::
271 ~Thermostat_impl ()
273 // Intentionally empty.
276 // IDL get_nominal operation.
278 CCS::TempType
279 Thermostat_impl::get_nominal ()
281 return get_nominal_temp ();
284 // IDL set_nominal operation.
286 CCS::TempType
287 Thermostat_impl::set_nominal (CCS::TempType new_temp)
289 return set_nominal_temp (new_temp);
292 //----------------------------------------------------------------
294 // Helper function to add an entry to the asset map.
296 void
297 Controller_impl::
298 add_impl (CCS::AssetType anum)
300 m_assets.insert (anum);
303 // Helper function to remove an entry from the asset map.
305 void
306 Controller_impl::
307 remove_impl (CCS::AssetType anum)
309 m_assets.erase (anum);
312 // Helper function to locate a servant in the asset map.
314 bool
315 Controller_impl::exists (CCS::AssetType anum)
317 return m_assets.find (anum) != m_assets.end ();
320 // Constructor
322 Controller_impl::
323 Controller_impl (PortableServer::POA_ptr poa, const char * asset_file)
324 : m_poa (PortableServer::POA::_duplicate (poa)),
325 m_asset_file (asset_file)
327 std::ifstream afile (m_asset_file.in (), std::ios::in|std::ios::out);//, 0666);
328 if (!afile) {
329 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
330 throw 0;
332 CCS::AssetType anum;
333 while (afile >> anum)
334 m_assets.insert (anum);
335 // afile.close ();
336 // if (!afile) {
337 // cerr << "Cannot close " << m_asset_file.in () << endl;
338 // throw 0;
339 // }
342 // Destructor
344 Controller_impl::
345 ~Controller_impl ()
347 // Write out the current set of asset numbers
348 // and clean up all servant instances.
349 std::ofstream afile (m_asset_file.in ());
350 if (!afile) {
351 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
352 assert (0);
354 AssetSet::iterator i;
355 for (i = m_assets.begin (); i != m_assets.end (); i++) {
356 afile << *i << std::endl;
357 if (!afile) {
358 std::cerr << "Cannot update " << m_asset_file.in () << std::endl;
359 assert (0);
362 // afile.close ();
363 // if (!afile) {
364 // cerr << "Cannot close " << m_asset_file.in () << endl;
365 // assert (0);
366 // }
369 CCS::Thermometer_ptr
370 Controller_impl::create_thermometer (CCS::AssetType anum, const char * loc)
373 ACE_GUARD (ACE_Mutex, ace_mon, m_assets_mutex);
375 if (anum % 2 == 0)
376 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
377 if (exists (anum))
378 throw CCS::Controller::DuplicateAsset ();
380 assert (ICP_online (anum) == 0);
381 assert (ICP_set (anum, "location", loc) == 0);
382 add_impl (anum);
385 return make_dref (m_poa.in (), anum);
388 CCS::Thermostat_ptr
389 Controller_impl::
390 create_thermostat (
391 CCS::AssetType anum,
392 const char* loc,
393 CCS::TempType temp)
396 ACE_GUARD (ACE_Mutex, ace_mon, m_assets_mutex);
399 if (anum % 2 != 0)
400 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
401 if (exists (anum))
402 throw CCS::Controller::DuplicateAsset ();
404 assert (ICP_online (anum) == 0);
405 assert (ICP_set (anum, "location", loc) == 0);
406 // Set the nominal temperature.
407 if (ICP_set (anum, "nominal_temp", &temp) != 0) {
408 // If ICP_set () failed, read this thermostat's minimum
409 // and maximum so we can initialize the BadTemp exception.
410 CCS::Thermostat::BtData btd;
411 ICP_get (
412 anum, "MIN_TEMP",
413 &btd.min_permitted, sizeof (btd.min_permitted)
415 ICP_get (
416 anum, "MAX_TEMP",
417 &btd.max_permitted, sizeof (btd.max_permitted)
419 btd.requested = temp;
420 btd.error_msg = CORBA::string_dup (
421 temp > btd.max_permitted ? "Too hot" : "Too cold"
423 throw CCS::Thermostat::BadTemp (btd);
426 add_impl (anum);
429 CORBA::Object_var obj = make_dref (m_poa.in (), anum);
430 return CCS::Thermostat::_narrow (obj.in ());
433 // IDL list operation.
435 CCS::Controller::ThermometerSeq *
436 Controller_impl::list ()
438 // Create a new thermometer sequence. Because we know
439 // the number of elements we will put onto the sequence,
440 // we use the maximum constructor.
441 CCS::Controller::ThermometerSeq_var listv
442 = new CCS::Controller::ThermometerSeq (m_assets.size ());
443 listv->length (m_assets.size ());
445 AssetSet tmp_assets;
447 ACE_GUARD (ACE_Mutex, ace_mon, m_assets_mutex);
448 tmp_assets = m_assets;
451 // Loop over the m_assets set and create a
452 // reference for each device.
453 CORBA::ULong count = 0;
454 AssetSet::iterator i;
455 for (i = tmp_assets.begin (); i != tmp_assets.end (); i++)
456 listv[count++] = make_dref (m_poa.in (), *i);
457 return listv._retn ();
460 // IDL change operation.
462 void
463 Controller_impl::
464 change (
465 const CCS::Controller::ThermostatSeq & tlist,
466 CORBA::Short delta
469 CCS::Controller::EChange ec; // Just in case we need it
471 // We cannot add a delta value to a thermostat's temperature
472 // directly, so for each thermostat, we read the nominal
473 // temperature, add the delta value to it, and write
474 // it back again.
475 for (CORBA::ULong i = 0; i < tlist.length (); i++) {
476 if (CORBA::is_nil (tlist[i]))
477 continue; // Skip nil references
479 // Read nominal temp and update it.
480 CCS::TempType tnom = tlist[i]->get_nominal ();
481 tnom += delta;
482 try {
483 tlist[i]->set_nominal (tnom);
485 catch (const CCS::Thermostat::BadTemp &bt) {
486 // If the update failed because the temperature
487 // is out of range, we add the thermostat's info
488 // to the errors sequence.
489 CORBA::ULong len = ec.errors.length ();
490 ec.errors.length (len + 1);
491 ec.errors[len].tmstat_ref = tlist[i].in ();
492 ec.errors[len].info = bt.details;
496 // If we encountered errors in the above loop,
497 // we will have added elements to the errors sequence.
498 if (ec.errors.length () != 0)
499 throw ec;
502 // IDL find operation
504 void
505 Controller_impl::
506 find (CCS::Controller::SearchSeq & slist)
508 // Loop over input list and lookup each device.
509 CORBA::ULong listlen = slist.length ();
510 for (CORBA::ULong i = 0; i < listlen; i++) {
511 AssetSet::iterator where; // Iterator for asset set
512 int num_found = 0; // Num matched per iteration
514 // Assume we will not find a matching device.
515 slist[i].device = CCS::Thermometer::_nil ();
517 // Work out whether we are searching by asset,
518 // model, or location.
519 CCS::Controller::SearchCriterion sc = slist[i].key._d ();
520 if (sc == CCS::Controller::ASSET) {
521 // Search for matching asset number.
522 bool make = false;
523 CCS::AssetType num = 0;
525 ACE_GUARD (ACE_Mutex, ace_mon, m_assets_mutex);
526 where = m_assets.find (slist[i].key.asset_num ());
527 if (where != m_assets.end ()) {
528 num = *where;
529 make = true;
532 if (make)
533 slist[i].device = make_dref (m_poa.in (), num);
534 } else {
535 // Search for model or location string.
536 const char *search_str;
537 if (sc == CCS::Controller::LOCATION)
538 search_str = slist[i].key.loc ();
539 else
540 search_str = slist[i].key.model_desc ();
542 // Find first matching device (if any).
543 where = find_if (
544 m_assets.begin (), m_assets.end (),
545 StrFinder (sc, search_str)
548 // While there are matches...
549 while (where != m_assets.end ()) {
550 if (num_found == 0) {
551 // First match overwrites reference
552 // in search record.
553 slist[i].device = make_dref (m_poa.in (), *where);
554 } else {
555 // Further matches each append a new
556 // element to the search sequence.
557 CORBA::ULong len = slist.length ();
558 slist.length (len + 1);
559 slist[len].key = slist[i].key;
560 slist[len].device = make_dref (m_poa.in (), *where);
562 num_found++;
564 // Find next matching device with this key.
565 where = find_if (
566 ++where, m_assets.end (),
567 StrFinder (sc, search_str)
574 //----------------------------------------------------------------
576 DeviceLocator_impl::
577 DeviceLocator_impl (Controller_impl * ctrl) : m_ctrl (ctrl)
579 // Intentionally empty
582 PortableServer::Servant
583 DeviceLocator_impl::
584 preinvoke (
585 const PortableServer::ObjectId & oid,
586 PortableServer::POA_ptr /* poa */ ,
587 const char * operation,
588 void * & /* cookie */
591 // Convert object id into asset number.
592 CORBA::String_var oid_string;
593 try {
594 oid_string = PortableServer::ObjectId_to_string (oid);
595 } catch (const CORBA::BAD_PARAM &) {
596 throw CORBA::OBJECT_NOT_EXIST ();
599 istrstream istr (oid_string.in ());
600 CCS::AssetType anum;
601 istr >> anum;
602 if (istr.fail ())
603 throw CORBA::OBJECT_NOT_EXIST ();
605 ACE_GUARD (ACE_Mutex, ace_mon, m_ctrl->m_assets_mutex);
607 // Check whether the device is known.
608 if (!m_ctrl->exists (anum))
609 throw CORBA::OBJECT_NOT_EXIST ();
611 // Look at the object map to find out whether
612 // we have a servant in memory.
613 Thermometer_impl * servant;
614 ActiveObjectMap::iterator servant_pos = m_aom.find (anum);
615 if (servant_pos == m_aom.end ()) {
616 // No servant in memory. If evictor queue is full,
617 // evict servant at head of queue.
618 if (m_eq.size () == MAX_EQ_SIZE) {
619 servant = m_eq.back ();
620 m_aom.erase (servant->m_anum);
621 m_eq.pop_back ();
622 servant->_remove_ref ();
624 // Instantiate correct type of servant.
625 char buf[32];
626 assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0);
627 if (ACE_OS::strcmp (buf, "Sens-A-Temp") == 0)
628 servant = new Thermometer_impl (anum);
629 else
630 servant = new Thermostat_impl (anum);
631 } else {
632 // Servant already in memory.
633 servant = * (servant_pos->second); // Remember servant
634 m_eq.erase (servant_pos->second); // Remove from queue
636 // If operation is "remove", also remove entry from
637 // active object map -- the object is about to be deleted.
638 if (ACE_OS::strcmp (operation, "remove") == 0)
639 m_aom.erase (servant_pos);
642 // We found a servant, or just instantiated it.
643 // If the operation is not a remove, move
644 // the servant to the tail of the evictor queue
645 // and update its queue position in the map.
646 if (ACE_OS::strcmp (operation, "remove") != 0) {
647 m_eq.push_front (servant);
648 m_aom[anum] = m_eq.begin ();
649 } else {
650 m_ctrl->remove_impl (anum);
653 return servant;
656 //----------------------------------------------------------------
659 ACE_TMAIN(int argc, ACE_TCHAR *argv[])
661 try {
662 // Initialize orb
663 CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);
665 // Get reference to Root POA.
666 CORBA::Object_var obj
667 = orb->resolve_initial_references ("RootPOA");
668 PortableServer::POA_var poa
669 = PortableServer::POA::_narrow (obj.in ());
671 // Get POA manager
672 PortableServer::POAManager_var poa_mgr = poa->the_POAManager ();
674 // Create a policy list. We use persistent objects with
675 // user-assigned IDs, and explicit activation.
676 CORBA::PolicyList policy_list;
677 policy_list.length (3);
678 policy_list[0] = poa->create_lifespan_policy (
679 PortableServer::TRANSIENT // REVISIT
681 policy_list[1] = poa->create_id_assignment_policy (
682 PortableServer::USER_ID
684 policy_list[2] = poa->create_implicit_activation_policy (
685 PortableServer::NO_IMPLICIT_ACTIVATION
688 // Create a POA for the controller.
689 PortableServer::POA_var ctrl_poa
690 = poa->create_POA ("CtrlPOA", poa_mgr.in (), policy_list);
692 policy_list.length (5);
693 policy_list[3] = poa->create_request_processing_policy (
694 PortableServer::USE_SERVANT_MANAGER
696 policy_list[4] = poa->create_servant_retention_policy (
697 PortableServer::NON_RETAIN
700 // Create a POA for the devices.
701 PortableServer::POA_var dev_poa
702 = ctrl_poa->create_POA ("DevPOA", poa_mgr.in (), policy_list);
704 // Create a controller and set static m_ctrl member
705 // for thermostats and thermometers.
706 Controller_impl ctrl_servant (dev_poa.in (), "/tmp/CCS_assets");
707 Thermometer_impl::m_ctrl = &ctrl_servant;
709 obj = ctrl_servant._this ();
711 // Write a reference for the controller to stdout.
712 CORBA::String_var str = orb->object_to_string (obj.in ());
713 std::cout << str.in () << std::endl << std::endl;
715 // Instantiate the servant locator for devices.
716 PortableServer::ServantManager_var locator =
717 new DeviceLocator_impl (&ctrl_servant);
719 // Set servant locator.
720 dev_poa->set_servant_manager (locator.in ());
722 // Activate the POA manager.
723 poa_mgr->activate ();
725 // Accept requests
726 orb->run ();
728 catch (const CORBA::Exception & e) {
729 std::cerr << "Uncaught CORBA exception: "
730 << e
731 << std::endl;
732 return 1;
734 catch (...) {
735 assert (0); // Uncaught exception, dump core
737 return 0;