ACE+TAO-6_5_17
[ACE_TAO.git] / TAO / examples / Advanced / ch_18 / server.cpp
blob6f3408411badc7dc3b425e8f24858034c953d52e
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) {
263 // If ICP_set () failed, read this thermostat's minimum
264 // and maximum so we can initialize the BadTemp exception.
265 CCS::Thermostat::BtData btd;
266 ICP_get (
267 m_anum, "MIN_TEMP",
268 &btd.min_permitted, sizeof (btd.min_permitted)
270 ICP_get (
271 m_anum, "MAX_TEMP",
272 &btd.max_permitted, sizeof (btd.max_permitted)
274 btd.requested = new_temp;
275 btd.error_msg = CORBA::string_dup (
276 new_temp > btd.max_permitted ? "Too hot" : "Too cold"
278 throw CCS::Thermostat::BadTemp (btd);
280 return old_temp;
283 // Constructor.
285 Thermostat_impl::
286 Thermostat_impl (CCS::AssetType anum) : Thermometer_impl (anum)
288 // Intentionally empty.
291 // Destructor.
293 Thermostat_impl::
294 ~Thermostat_impl ()
296 // Intentionally empty.
299 // IDL get_nominal operation.
301 CCS::TempType
302 Thermostat_impl::get_nominal ()
304 return get_nominal_temp ();
307 // IDL set_nominal operation.
309 CCS::TempType
310 Thermostat_impl::set_nominal (CCS::TempType new_temp)
312 return set_nominal_temp (new_temp);
315 //----------------------------------------------------------------
317 // Helper function to add an entry to the asset map.
319 void
320 Controller_impl::
321 add_impl (CCS::AssetType anum, Thermometer_impl * tip)
323 m_assets[anum] = tip;
326 // Helper function to remove an entry from the asset map.
328 void
329 Controller_impl::
330 remove_impl (CCS::AssetType anum)
332 m_assets.erase (anum);
335 // Helper function to locate a servant in the asset map.
337 bool
338 Controller_impl::
339 exists (CCS::AssetType anum)
341 return m_assets.find (anum) != m_assets.end ();
344 // Constructor
346 Controller_impl::
347 Controller_impl (
348 PortableServer::POA_ptr poa,
349 const char * asset_file)
350 : m_poa (PortableServer::POA::_duplicate (poa)),
351 m_asset_file (asset_file)
353 std::ifstream afile (m_asset_file.in (), std::ios::in|std::ios::out);//, 0666);
354 if (!afile) {
355 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
356 throw 0;
358 CCS::AssetType anum;
359 while (afile >> anum)
360 m_assets[anum] = 0;
361 //afile.close ();
362 //if (!afile) {
363 // cerr << "Cannot close " << m_asset_file << endl;
364 // throw 0;
368 // Destructor
370 Controller_impl::
371 ~Controller_impl ()
373 // Write out the current set of asset numbers
374 // and clean up all servant instances.
375 std::ofstream afile (m_asset_file.in ());
376 if (!afile) {
377 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
378 assert (0);
380 AssetMap::iterator i;
381 for (i = m_assets.begin (); i != m_assets.end (); i++) {
382 afile << i->first << std::endl;
383 if (!afile) {
384 std::cerr << "Cannot update " << m_asset_file.in () << std::endl;
385 assert (0);
387 delete i->second;
389 //afile.close ();
390 //if (!afile) {
391 // cerr << "Cannot close " << m_asset_file << endl;
392 // assert (0);
396 CCS::Thermometer_ptr
397 Controller_impl::create_thermometer (CCS::AssetType anum, const char * loc)
399 if (anum % 2 == 0)
400 throw CORBA::BAD_PARAM (); // Thermometers have odd 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 add_impl (anum, 0);
407 return make_dref (m_poa.in (), anum);
410 CCS::Thermostat_ptr
411 Controller_impl::
412 create_thermostat (
413 CCS::AssetType anum,
414 const char* loc,
415 CCS::TempType temp)
417 if (anum % 2 != 0)
418 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
419 if (exists (anum))
420 throw CCS::Controller::DuplicateAsset ();
422 assert (ICP_online (anum) == 0);
423 assert (ICP_set (anum, "location", loc) == 0);
424 // Set the nominal temperature.
425 if (ICP_set (anum, "nominal_temp", &temp) != 0) {
427 // If ICP_set () failed, read this thermostat's minimum
428 // and maximum so we can initialize the BadTemp exception.
429 CCS::Thermostat::BtData btd;
430 ICP_get (
431 anum, "MIN_TEMP",
432 &btd.min_permitted, sizeof (btd.min_permitted)
434 ICP_get (
435 anum, "MAX_TEMP",
436 &btd.max_permitted, sizeof (btd.max_permitted)
438 btd.requested = temp;
439 btd.error_msg = CORBA::string_dup (
440 temp > btd.max_permitted ? "Too hot" : "Too cold"
442 ICP_offline (anum);
443 throw CCS::Thermostat::BadTemp (btd);
446 add_impl (anum, 0);
447 CORBA::Object_var obj = make_dref (m_poa.in (), anum);
448 return CCS::Thermostat::_narrow (obj.in ());
451 // IDL list operation.
453 CCS::Controller::ThermometerSeq *
454 Controller_impl::list ()
456 // Create a new thermometer sequence. Because we know
457 // the number of elements we will put onto the sequence,
458 // we use the maximum constructor.
459 CCS::Controller::ThermometerSeq_var listv
460 = new CCS::Controller::ThermometerSeq (m_assets.size ());
461 listv->length (m_assets.size ());
463 // Loop over the m_assets set and create a
464 // reference for each device.
465 CORBA::ULong count = 0;
466 AssetMap::iterator i;
467 for (i = m_assets.begin (); i != m_assets.end (); i++)
468 listv[count++] = make_dref (m_poa.in (), i->first);
469 return listv._retn ();
472 // IDL change operation.
474 void
475 Controller_impl::
476 change (
477 const CCS::Controller::ThermostatSeq & tlist,
478 CORBA::Short delta)
480 CCS::Controller::EChange ec; // Just in case we need it
482 // We cannot add a delta value to a thermostat's temperature
483 // directly, so for each thermostat, we read the nominal
484 // temperature, add the delta value to it, and write
485 // it back again.
486 for (CORBA::ULong i = 0; i < tlist.length (); i++) {
487 if (CORBA::is_nil (tlist[i]))
488 continue; // Skip nil references
490 // Read nominal temp and update it.
491 CCS::TempType tnom = tlist[i]->get_nominal ();
492 tnom += delta;
493 try {
494 tlist[i]->set_nominal (tnom);
496 catch (const CCS::Thermostat::BadTemp &bt) {
497 // If the update failed because the temperature
498 // is out of range, we add the thermostat's info
499 // to the errors sequence.
500 CORBA::ULong len = ec.errors.length ();
501 ec.errors.length (len + 1);
502 ec.errors[len].tmstat_ref = tlist[i].in ();
503 ec.errors[len].info = bt.details;
507 // If we encountered errors in the above loop,
508 // we will have added elements to the errors sequence.
509 if (ec.errors.length () != 0)
510 throw ec;
513 // IDL find operation
515 void
516 Controller_impl::find (CCS::Controller::SearchSeq & slist)
518 // Loop over input list and lookup each device.
519 CORBA::ULong listlen = slist.length ();
520 for (CORBA::ULong i = 0; i < listlen; i++) {
522 AssetMap::iterator where; // Iterator for asset set
523 int num_found = 0; // Num matched per iteration
525 // Assume we will not find a matching device.
526 slist[i].device = CCS::Thermometer::_nil ();
528 // Work out whether we are searching by asset,
529 // model, or location.
530 CCS::Controller::SearchCriterion sc = slist[i].key._d ();
531 if (sc == CCS::Controller::ASSET) {
532 // Search for matching asset number.
533 where = m_assets.find (slist[i].key.asset_num ());
534 if (where != m_assets.end ())
535 slist[i].device = make_dref (m_poa.in (), where->first);
536 } else {
537 // Search for model or location string.
538 const char *search_str;
539 if (sc == CCS::Controller::LOCATION)
540 search_str = slist[i].key.loc ();
541 else
542 search_str = slist[i].key.model_desc ();
544 // Find first matching device (if any).
545 where = find_if (
546 m_assets.begin (), m_assets.end (),
547 StrFinder (sc, search_str)
550 // While there are matches...
551 while (where != m_assets.end ()) {
552 if (num_found == 0) {
553 // First match overwrites reference
554 // in search record.
555 slist[i].device = make_dref (m_poa.in (), where->first);
556 } else {
557 // Further matches each append a new
558 // element to the search sequence.
559 CORBA::ULong len = slist.length ();
560 slist.length (len + 1);
561 slist[len].key = slist[i].key;
562 slist[len].device = make_dref (m_poa.in (), where->first);
564 num_found++;
566 // Find next matching device with this key.
567 where = find_if (
568 ++where, m_assets.end (),
569 StrFinder (sc, search_str)
576 //----------------------------------------------------------------
578 DeviceLocator_impl::
579 DeviceLocator_impl (Controller_impl * ctrl) : m_ctrl (ctrl)
581 // Intentionally empty
584 PortableServer::Servant
585 DeviceLocator_impl::
586 preinvoke (
587 const PortableServer::ObjectId & oid,
588 PortableServer::POA_ptr /* poa */,
589 const char * operation,
590 void * & /* cookie */)
592 // Convert object id into asset number.
593 CORBA::String_var oid_string;
594 try {
595 oid_string = PortableServer::ObjectId_to_string (oid);
596 } catch (const CORBA::BAD_PARAM &) {
597 throw CORBA::OBJECT_NOT_EXIST ();
600 if (ACE_OS::strcmp (oid_string.in (), Controller_oid) == 0)
601 return m_ctrl;
603 istrstream istr (oid_string.in ());
604 CCS::AssetType anum;
605 istr >> anum;
606 if (istr.fail ())
607 throw CORBA::OBJECT_NOT_EXIST ();
609 // Check whether the device is known.
610 if (!m_ctrl->exists (anum))
611 throw CORBA::OBJECT_NOT_EXIST ();
613 // Look at the object map to find out whether
614 // we have a servant in memory.
615 Thermometer_impl * servant;
616 ActiveObjectMap::iterator servant_pos = m_aom.find (anum);
617 if (servant_pos == m_aom.end ()) {
618 // No servant in memory. If evictor queue is full,
619 // evict servant at head of queue.
620 if (m_eq.size () == MAX_EQ_SIZE) {
621 servant = m_eq.back ();
622 m_aom.erase (servant->m_anum);
623 m_eq.pop_back ();
624 delete servant;
626 // Instantiate correct type of servant.
627 char buf[32];
628 assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0);
629 if (ACE_OS::strcmp (buf, "Sens-A-Temp") == 0)
630 servant = new Thermometer_impl (anum);
631 else
632 servant = new Thermostat_impl (anum);
633 } else {
634 // Servant already in memory.
635 servant = * (servant_pos->second); // Remember servant
636 m_eq.erase (servant_pos->second); // Remove from queue
638 // If operation is "remove", also remove entry from
639 // active object map -- the object is about to be deleted.
640 if (ACE_OS::strcmp (operation, "remove") == 0)
641 m_aom.erase (servant_pos);
644 // We found a servant, or just instantiated it.
645 // If the operation is not a remove, move
646 // the servant to the tail of the evictor queue
647 // and update its queue position in the map.
648 if (ACE_OS::strcmp (operation, "remove") != 0) {
649 m_eq.push_front (servant);
650 m_aom[anum] = m_eq.begin ();
653 return servant;
656 //----------------------------------------------------------------
659 ACE_TMAIN(int argc, ACE_TCHAR *argv[])
661 CORBA::ORB_var orb;
663 try {
664 // Initialize orb
665 orb = CORBA::ORB_init (argc, argv);
667 // Get reference to Root POA.
668 CORBA::Object_var obj
669 = orb->resolve_initial_references ("RootPOA");
670 PortableServer::POA_var poa
671 = PortableServer::POA::_narrow (obj.in ());
673 // Get POA manager
674 PortableServer::POAManager_var poa_mgr = poa->the_POAManager ();
676 // Create a policy list. We use persistent objects with
677 // user-assigned IDs, and explicit activation.
678 CORBA::PolicyList policy_list;
679 policy_list.length (6);
680 policy_list[0] = poa->create_lifespan_policy (
681 PortableServer::TRANSIENT // REVISIT
683 policy_list[1] = poa->create_id_assignment_policy (
684 PortableServer::USER_ID
686 policy_list[2] = poa->create_implicit_activation_policy (
687 PortableServer::NO_IMPLICIT_ACTIVATION
689 policy_list[3] = poa->create_request_processing_policy (
690 PortableServer::USE_SERVANT_MANAGER
692 policy_list[4] = poa->create_servant_retention_policy (
693 PortableServer::NON_RETAIN
695 policy_list[5] = poa->create_thread_policy (
696 PortableServer::SINGLE_THREAD_MODEL
699 // Create a POA for all CCS elements.
700 PortableServer::POA_var ccs_poa
701 = poa->create_POA ("CCS_POA", poa_mgr.in (), policy_list);
703 // Create a controller and set static m_ctrl member
704 // for thermostats and thermometers.
705 Controller_impl ctrl_servant (ccs_poa.in (), "/tmp/CCS_assets");
706 Thermometer_impl::m_ctrl = &ctrl_servant;
708 // Create a reference for the controller and
709 // create the corresponding CORBA object.
710 PortableServer::ObjectId_var oid
711 = PortableServer::string_to_ObjectId (Controller_oid);
712 CORBA::Object_var ctrl
713 = ccs_poa->create_reference_with_id (
714 oid.in (), "IDL:acme.com/CCS/Controller:1.0"
717 // Get reference to initial naming context.
718 CosNaming::NamingContext_var inc
719 = resolve_init<CosNaming::NamingContext> (
720 orb.in (), "NameService"
723 // Attempt to create CCS context.
724 CosNaming::Name n;
725 n.length (1);
726 n[0].id = CORBA::string_dup ("CCS");
727 try {
728 CosNaming::NamingContext_var nc
729 = inc->bind_new_context (n);
730 } catch (const CosNaming::NamingContext::AlreadyBound &) {
731 // Fine, CCS context already exists.
734 // Force binding of controller reference to make
735 // sure it is always up-to-date.
736 n.length (2);
737 n[1].id = CORBA::string_dup ("Controller");
738 inc->rebind (n, ctrl.in ());
740 // Instantiate the servant locator for devices.
741 PortableServer::ServantManager_var locator =
742 new DeviceLocator_impl (&ctrl_servant);
744 // Set servant locator.
745 ccs_poa->set_servant_manager (locator.in ());
747 // Activate the POA manager.
748 poa_mgr->activate ();
750 // Accept requests
751 orb->run ();
753 catch (const CORBA::Exception & e) {
754 std::cerr << "Uncaught CORBA exception: "
755 << e
756 << std::endl;
757 return 1;
759 catch (...) {
760 assert (0); // Uncaught exception, dump core
762 return 0;