Changes to attempt to silence bcc64x
[ACE_TAO.git] / TAO / examples / Advanced / ch_18 / server.cpp
blob78903c6cff0a0fe13fb39819b41ef6f751c2a38d
2 //=============================================================================
3 /**
4 * @file server.cpp
6 * @author Source code used in TAO has been modified and adapted from thecode provided in the book
7 * @author "Advanced CORBA Programming with C++"by Michi Henning and Steve Vinoski. Copyright1999. Addison-Wesley
8 * @author Reading
9 * @author MA. Used with permission ofAddison-Wesley.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"
19 #include "orbsvcs/CosNamingC.h"
21 const char * Controller_oid = "Controller";
22 const unsigned int DeviceLocator_impl::MAX_EQ_SIZE = 100;
24 //----------------------------------------------------------------
26 template<class T>
27 typename T::_ptr_type
28 resolve_init (CORBA::ORB_ptr orb, const char * id)
30 CORBA::Object_var obj;
31 try {
32 obj = orb->resolve_initial_references (id);
34 catch (const CORBA::ORB::InvalidName &) {
35 throw;
37 catch (const CORBA::Exception & e) {
38 std::cerr << "Cannot get initial reference for "
39 << id << ": "
40 << e
41 << std::endl;
42 throw 0;
44 assert (!CORBA::is_nil (obj.in ()));
46 typename T::_var_type ref;
47 try {
48 ref = T::_narrow (obj.in ());
50 catch (const CORBA::Exception & e) {
51 std::cerr << "Cannot narrow reference for "
52 << id << ": "
53 << e
54 << std::endl;
55 throw 0;
57 if (CORBA::is_nil (ref.in ())) {
58 std::cerr << "Incorrect type of reference for "
59 << id << std::endl;
60 throw 0;
62 return ref._retn ();
65 //----------------------------------------------------------------
67 // Generic ostream inserter for exceptions. Inserts the exception
68 // name, if available, and the repository ID otherwise.
70 #if 0 // This inserter is not needed for TAO.
72 static ostream &
73 operator<< (ostream & os, const CORBA::Exception & e)
75 CORBA::Any tmp;
76 tmp <<= e;
78 CORBA::TypeCode_var tc = tmp.type ();
79 const char * p = tc->name ();
80 if (*p != '\0')
81 os << p;
82 else
83 os << tc->id ();
84 return os;
87 #endif
89 //----------------------------------------------------------------
91 // Helper function to create object references.
93 static CCS::Thermometer_ptr
94 make_dref (PortableServer::POA_ptr poa, CCS::AssetType anum)
96 // Convert asset number to OID.
97 ostrstream ostr;
98 ostr << anum << ends;
99 char * anum_str = ostr.str ();
100 PortableServer::ObjectId_var oid
101 = PortableServer::string_to_ObjectId (anum_str);
102 delete[] anum_str;
104 // Look at the model via the network to determine
105 // the repository ID.
106 char buf[32];
107 assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0);
108 const char * rep_id = ACE_OS::strcmp (buf, "Sens-A-Temp") == 0
109 ? "IDL:acme.com/CCS/Thermometer:1.0"
110 : "IDL:acme.com/CCS/Thermostat:1.0";
112 // Make a new reference.
113 CORBA::Object_var obj
114 = poa->create_reference_with_id (oid.in (), rep_id);
115 return CCS::Thermometer::_narrow (obj.in ());
118 //----------------------------------------------------------------
120 Controller_impl * Thermometer_impl::m_ctrl; // static member
122 // Helper function to read the model string from a device.
124 CCS::ModelType
125 Thermometer_impl::
126 get_model ()
128 char buf[32];
129 assert (ICP_get (m_anum, "model", buf, sizeof (buf)) == 0);
130 return CORBA::string_dup (buf);
133 // Helper function to read the temperature from a device.
135 CCS::TempType
136 Thermometer_impl::
137 get_temp ()
139 short temp;
140 assert (ICP_get (m_anum, "temperature", &temp, sizeof (temp)) == 0);
141 return temp;
144 // Helper function to read the location from a device.
146 CCS::LocType
147 Thermometer_impl::
148 get_loc ()
150 char buf[32];
151 assert (ICP_get (m_anum, "location", buf, sizeof (buf)) == 0);
152 return CORBA::string_dup (buf);
155 // Helper function to set the location of a device.
157 void
158 Thermometer_impl::
159 set_loc (const char * loc)
161 assert (ICP_set (m_anum, "location", loc) == 0);
164 // Constructor.
166 Thermometer_impl::
167 Thermometer_impl (CCS::AssetType anum) : m_anum (anum)
169 m_ctrl->add_impl (anum, this); // Add self to controller's set
172 // Destructor.
174 Thermometer_impl::
175 ~Thermometer_impl ()
177 if (m_ctrl->exists (m_anum))
178 m_ctrl->add_impl (m_anum, 0); // Clear servant pointer
181 // IDL model attribute.
183 CCS::ModelType
184 Thermometer_impl::model ()
186 return get_model ();
189 // IDL asset_num attribute.
191 CCS::AssetType
192 Thermometer_impl::asset_num ()
194 return m_anum;
197 // IDL temperature attribute.
199 CCS::TempType
200 Thermometer_impl::temperature ()
202 return get_temp ();
205 // IDL location attribute accessor.
207 CCS::LocType
208 Thermometer_impl::location ()
210 return get_loc ();
213 // IDL remove operation.
215 void
216 Thermometer_impl::remove ()
218 m_ctrl->remove_impl (m_anum);
219 assert (ICP_offline (m_anum) == 0);
220 //delete this;
223 // IDL location attribute modifier.
225 void
226 Thermometer_impl::location (const char *loc)
228 set_loc (loc);
231 //----------------------------------------------------------------
233 // Helper function to get a thermostat's nominal temperature.
235 CCS::TempType
236 Thermostat_impl::
237 get_nominal_temp ()
239 short temp;
240 assert (ICP_get (m_anum, "nominal_temp", &temp, sizeof (temp)) == 0);
241 return temp;
244 // Helper function to set a thermostat's nominal temperature.
246 CCS::TempType
247 Thermostat_impl::set_nominal_temp (CCS::TempType new_temp)
249 short old_temp;
251 // We need to return the previous nominal temperature,
252 // so we first read the current nominal temperature before
253 // changing it.
254 assert (
255 ICP_get (
256 m_anum, "nominal_temp", &old_temp, sizeof (old_temp)
257 ) == 0
260 // Now set the nominal temperature to the new value.
261 if (ICP_set (m_anum, "nominal_temp", &new_temp) != 0) {
262 // If ICP_set () failed, read this thermostat's minimum
263 // and maximum so we can initialize the BadTemp exception.
264 CCS::Thermostat::BtData btd;
265 ICP_get (
266 m_anum, "MIN_TEMP",
267 &btd.min_permitted, sizeof (btd.min_permitted)
269 ICP_get (
270 m_anum, "MAX_TEMP",
271 &btd.max_permitted, sizeof (btd.max_permitted)
273 btd.requested = new_temp;
274 btd.error_msg = CORBA::string_dup (
275 new_temp > btd.max_permitted ? "Too hot" : "Too cold"
277 throw CCS::Thermostat::BadTemp (btd);
279 return old_temp;
282 // Constructor.
284 Thermostat_impl::
285 Thermostat_impl (CCS::AssetType anum) : Thermometer_impl (anum)
287 // Intentionally empty.
290 // Destructor.
292 Thermostat_impl::
293 ~Thermostat_impl ()
295 // Intentionally empty.
298 // IDL get_nominal operation.
300 CCS::TempType
301 Thermostat_impl::get_nominal ()
303 return get_nominal_temp ();
306 // IDL set_nominal operation.
308 CCS::TempType
309 Thermostat_impl::set_nominal (CCS::TempType new_temp)
311 return set_nominal_temp (new_temp);
314 //----------------------------------------------------------------
316 // Helper function to add an entry to the asset map.
318 void
319 Controller_impl::
320 add_impl (CCS::AssetType anum, Thermometer_impl * tip)
322 m_assets[anum] = tip;
325 // Helper function to remove an entry from the asset map.
327 void
328 Controller_impl::
329 remove_impl (CCS::AssetType anum)
331 m_assets.erase (anum);
334 // Helper function to locate a servant in the asset map.
336 bool
337 Controller_impl::
338 exists (CCS::AssetType anum)
340 return m_assets.find (anum) != m_assets.end ();
343 // Constructor
345 Controller_impl::
346 Controller_impl (
347 PortableServer::POA_ptr poa,
348 const char * asset_file)
349 : m_poa (PortableServer::POA::_duplicate (poa)),
350 m_asset_file (asset_file)
352 std::ifstream afile (m_asset_file.in (), std::ios::in|std::ios::out);//, 0666);
353 if (!afile) {
354 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
355 throw 0;
357 CCS::AssetType anum;
358 while (afile >> anum)
359 m_assets[anum] = 0;
360 //afile.close ();
361 //if (!afile) {
362 // cerr << "Cannot close " << m_asset_file << endl;
363 // throw 0;
367 // Destructor
369 Controller_impl::
370 ~Controller_impl ()
372 // Write out the current set of asset numbers
373 // and clean up all servant instances.
374 std::ofstream afile (m_asset_file.in ());
375 if (!afile) {
376 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
377 assert (0);
379 AssetMap::iterator i;
380 for (i = m_assets.begin (); i != m_assets.end (); i++) {
381 afile << i->first << std::endl;
382 if (!afile) {
383 std::cerr << "Cannot update " << m_asset_file.in () << std::endl;
384 assert (0);
386 delete i->second;
388 //afile.close ();
389 //if (!afile) {
390 // cerr << "Cannot close " << m_asset_file << endl;
391 // assert (0);
395 CCS::Thermometer_ptr
396 Controller_impl::create_thermometer (CCS::AssetType anum, const char * loc)
398 if (anum % 2 == 0)
399 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
400 if (exists (anum))
401 throw CCS::Controller::DuplicateAsset ();
403 assert (ICP_online (anum) == 0);
404 assert (ICP_set (anum, "location", loc) == 0);
405 add_impl (anum, 0);
406 return make_dref (m_poa.in (), anum);
409 CCS::Thermostat_ptr
410 Controller_impl::
411 create_thermostat (
412 CCS::AssetType anum,
413 const char* loc,
414 CCS::TempType temp)
416 if (anum % 2 != 0)
417 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
418 if (exists (anum))
419 throw CCS::Controller::DuplicateAsset ();
421 assert (ICP_online (anum) == 0);
422 assert (ICP_set (anum, "location", loc) == 0);
423 // Set the nominal temperature.
424 if (ICP_set (anum, "nominal_temp", &temp) != 0) {
425 // If ICP_set () failed, read this thermostat's minimum
426 // and maximum so we can initialize the BadTemp exception.
427 CCS::Thermostat::BtData btd;
428 ICP_get (
429 anum, "MIN_TEMP",
430 &btd.min_permitted, sizeof (btd.min_permitted)
432 ICP_get (
433 anum, "MAX_TEMP",
434 &btd.max_permitted, sizeof (btd.max_permitted)
436 btd.requested = temp;
437 btd.error_msg = CORBA::string_dup (
438 temp > btd.max_permitted ? "Too hot" : "Too cold"
440 ICP_offline (anum);
441 throw CCS::Thermostat::BadTemp (btd);
444 add_impl (anum, 0);
445 CORBA::Object_var obj = make_dref (m_poa.in (), anum);
446 return CCS::Thermostat::_narrow (obj.in ());
449 // IDL list operation.
451 CCS::Controller::ThermometerSeq *
452 Controller_impl::list ()
454 // Create a new thermometer sequence. Because we know
455 // the number of elements we will put onto the sequence,
456 // we use the maximum constructor.
457 CCS::Controller::ThermometerSeq_var listv
458 = new CCS::Controller::ThermometerSeq (m_assets.size ());
459 listv->length (m_assets.size ());
461 // Loop over the m_assets set and create a
462 // reference for each device.
463 CORBA::ULong count = 0;
464 AssetMap::iterator i;
465 for (i = m_assets.begin (); i != m_assets.end (); i++)
466 listv[count++] = make_dref (m_poa.in (), i->first);
467 return listv._retn ();
470 // IDL change operation.
472 void
473 Controller_impl::
474 change (
475 const CCS::Controller::ThermostatSeq & tlist,
476 CORBA::Short delta)
478 CCS::Controller::EChange ec; // Just in case we need it
480 // We cannot add a delta value to a thermostat's temperature
481 // directly, so for each thermostat, we read the nominal
482 // temperature, add the delta value to it, and write
483 // it back again.
484 for (CORBA::ULong i = 0; i < tlist.length (); i++) {
485 if (CORBA::is_nil (tlist[i]))
486 continue; // Skip nil references
488 // Read nominal temp and update it.
489 CCS::TempType tnom = tlist[i]->get_nominal ();
490 tnom += delta;
491 try {
492 tlist[i]->set_nominal (tnom);
494 catch (const CCS::Thermostat::BadTemp &bt) {
495 // If the update failed because the temperature
496 // is out of range, we add the thermostat's info
497 // to the errors sequence.
498 CORBA::ULong len = ec.errors.length ();
499 ec.errors.length (len + 1);
500 ec.errors[len].tmstat_ref = tlist[i].in ();
501 ec.errors[len].info = bt.details;
505 // If we encountered errors in the above loop,
506 // we will have added elements to the errors sequence.
507 if (ec.errors.length () != 0)
508 throw ec;
511 // IDL find operation
513 void
514 Controller_impl::find (CCS::Controller::SearchSeq & slist)
516 // Loop over input list and lookup each device.
517 CORBA::ULong listlen = slist.length ();
518 for (CORBA::ULong i = 0; i < listlen; i++) {
519 AssetMap::iterator where; // Iterator for asset set
520 int num_found = 0; // Num matched per iteration
522 // Assume we will not find a matching device.
523 slist[i].device = CCS::Thermometer::_nil ();
525 // Work out whether we are searching by asset,
526 // model, or location.
527 CCS::Controller::SearchCriterion sc = slist[i].key._d ();
528 if (sc == CCS::Controller::ASSET) {
529 // Search for matching asset number.
530 where = m_assets.find (slist[i].key.asset_num ());
531 if (where != m_assets.end ())
532 slist[i].device = make_dref (m_poa.in (), where->first);
533 } else {
534 // Search for model or location string.
535 const char *search_str;
536 if (sc == CCS::Controller::LOCATION)
537 search_str = slist[i].key.loc ();
538 else
539 search_str = slist[i].key.model_desc ();
541 // Find first matching device (if any).
542 where = find_if (
543 m_assets.begin (), m_assets.end (),
544 StrFinder (sc, search_str)
547 // While there are matches...
548 while (where != m_assets.end ()) {
549 if (num_found == 0) {
550 // First match overwrites reference
551 // in search record.
552 slist[i].device = make_dref (m_poa.in (), where->first);
553 } else {
554 // Further matches each append a new
555 // element to the search sequence.
556 CORBA::ULong len = slist.length ();
557 slist.length (len + 1);
558 slist[len].key = slist[i].key;
559 slist[len].device = make_dref (m_poa.in (), where->first);
561 num_found++;
563 // Find next matching device with this key.
564 where = find_if (
565 ++where, m_assets.end (),
566 StrFinder (sc, search_str)
573 //----------------------------------------------------------------
575 DeviceLocator_impl::
576 DeviceLocator_impl (Controller_impl * ctrl) : m_ctrl (ctrl)
578 // Intentionally empty
581 PortableServer::Servant
582 DeviceLocator_impl::
583 preinvoke (
584 const PortableServer::ObjectId & oid,
585 PortableServer::POA_ptr /* poa */,
586 const char * operation,
587 void * & /* cookie */)
589 // Convert object id into asset number.
590 CORBA::String_var oid_string;
591 try {
592 oid_string = PortableServer::ObjectId_to_string (oid);
593 } catch (const CORBA::BAD_PARAM &) {
594 throw CORBA::OBJECT_NOT_EXIST ();
597 if (ACE_OS::strcmp (oid_string.in (), Controller_oid) == 0)
598 return m_ctrl;
600 istrstream istr (oid_string.in ());
601 CCS::AssetType anum;
602 istr >> anum;
603 if (istr.fail ())
604 throw CORBA::OBJECT_NOT_EXIST ();
606 // Check whether the device is known.
607 if (!m_ctrl->exists (anum))
608 throw CORBA::OBJECT_NOT_EXIST ();
610 // Look at the object map to find out whether
611 // we have a servant in memory.
612 Thermometer_impl * servant;
613 ActiveObjectMap::iterator servant_pos = m_aom.find (anum);
614 if (servant_pos == m_aom.end ()) {
615 // No servant in memory. If evictor queue is full,
616 // evict servant at head of queue.
617 if (m_eq.size () == MAX_EQ_SIZE) {
618 servant = m_eq.back ();
619 m_aom.erase (servant->m_anum);
620 m_eq.pop_back ();
621 delete servant;
623 // Instantiate correct type of servant.
624 char buf[32];
625 assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0);
626 if (ACE_OS::strcmp (buf, "Sens-A-Temp") == 0)
627 servant = new Thermometer_impl (anum);
628 else
629 servant = new Thermostat_impl (anum);
630 } else {
631 // Servant already in memory.
632 servant = * (servant_pos->second); // Remember servant
633 m_eq.erase (servant_pos->second); // Remove from queue
635 // If operation is "remove", also remove entry from
636 // active object map -- the object is about to be deleted.
637 if (ACE_OS::strcmp (operation, "remove") == 0)
638 m_aom.erase (servant_pos);
641 // We found a servant, or just instantiated it.
642 // If the operation is not a remove, move
643 // the servant to the tail of the evictor queue
644 // and update its queue position in the map.
645 if (ACE_OS::strcmp (operation, "remove") != 0) {
646 m_eq.push_front (servant);
647 m_aom[anum] = m_eq.begin ();
650 return servant;
653 //----------------------------------------------------------------
656 ACE_TMAIN(int argc, ACE_TCHAR *argv[])
658 CORBA::ORB_var orb;
660 try {
661 // Initialize orb
662 orb = CORBA::ORB_init (argc, argv);
664 // Get reference to Root POA.
665 CORBA::Object_var obj
666 = orb->resolve_initial_references ("RootPOA");
667 PortableServer::POA_var poa
668 = PortableServer::POA::_narrow (obj.in ());
670 // Get POA manager
671 PortableServer::POAManager_var poa_mgr = poa->the_POAManager ();
673 // Create a policy list. We use persistent objects with
674 // user-assigned IDs, and explicit activation.
675 CORBA::PolicyList policy_list;
676 policy_list.length (6);
677 policy_list[0] = poa->create_lifespan_policy (
678 PortableServer::TRANSIENT // REVISIT
680 policy_list[1] = poa->create_id_assignment_policy (
681 PortableServer::USER_ID
683 policy_list[2] = poa->create_implicit_activation_policy (
684 PortableServer::NO_IMPLICIT_ACTIVATION
686 policy_list[3] = poa->create_request_processing_policy (
687 PortableServer::USE_SERVANT_MANAGER
689 policy_list[4] = poa->create_servant_retention_policy (
690 PortableServer::NON_RETAIN
692 policy_list[5] = poa->create_thread_policy (
693 PortableServer::SINGLE_THREAD_MODEL
696 // Create a POA for all CCS elements.
697 PortableServer::POA_var ccs_poa
698 = poa->create_POA ("CCS_POA", poa_mgr.in (), policy_list);
700 // Create a controller and set static m_ctrl member
701 // for thermostats and thermometers.
702 Controller_impl ctrl_servant (ccs_poa.in (), "/tmp/CCS_assets");
703 Thermometer_impl::m_ctrl = &ctrl_servant;
705 // Create a reference for the controller and
706 // create the corresponding CORBA object.
707 PortableServer::ObjectId_var oid
708 = PortableServer::string_to_ObjectId (Controller_oid);
709 CORBA::Object_var ctrl
710 = ccs_poa->create_reference_with_id (
711 oid.in (), "IDL:acme.com/CCS/Controller:1.0"
714 // Get reference to initial naming context.
715 CosNaming::NamingContext_var inc
716 = resolve_init<CosNaming::NamingContext> (
717 orb.in (), "NameService"
720 // Attempt to create CCS context.
721 CosNaming::Name n;
722 n.length (1);
723 n[0].id = CORBA::string_dup ("CCS");
724 try {
725 CosNaming::NamingContext_var nc
726 = inc->bind_new_context (n);
727 } catch (const CosNaming::NamingContext::AlreadyBound &) {
728 // Fine, CCS context already exists.
731 // Force binding of controller reference to make
732 // sure it is always up-to-date.
733 n.length (2);
734 n[1].id = CORBA::string_dup ("Controller");
735 inc->rebind (n, ctrl.in ());
737 // Instantiate the servant locator for devices.
738 PortableServer::ServantManager_var locator =
739 new DeviceLocator_impl (&ctrl_servant);
741 // Set servant locator.
742 ccs_poa->set_servant_manager (locator.in ());
744 // Activate the POA manager.
745 poa_mgr->activate ();
747 // Accept requests
748 orb->run ();
750 catch (const CORBA::Exception & e) {
751 std::cerr << "Uncaught CORBA exception: "
752 << e
753 << std::endl;
754 return 1;
756 catch (...) {
757 assert (0); // Uncaught exception, dump core
759 return 0;