More tests update
[ACE_TAO.git] / TAO / examples / Advanced / ch_12 / server.cpp
blobeb1414201b547bebcac826fe97e69a2736e65567
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"
20 // The following headers are #included automatically by ACE+TAO.
21 // Therefore, they don't need to be included explicitly.
22 // #include <fstream.h>
23 // #include <iostream.h>
25 const char *Controller_oid = "Controller";
26 const unsigned int DeviceLocator_impl::MAX_EQ_SIZE = 100;
27 // Generic ostream inserter for exceptions. Inserts the exception
28 // name, if available, and the repository ID otherwise.
30 #if 0 // This inserter may or may not be needed for your ORB.
32 static ostream &
33 operator<< (ostream & os, const CORBA::Exception & e)
35 CORBA::Any tmp;
36 tmp <<= e;
38 CORBA::TypeCode_var tc = tmp.type ();
39 const char * p = tc->name ();
40 if (*p != '\0')
41 os << p;
42 else
43 os << tc->id ();
44 return os;
47 #endif
49 // Helper function to create object references.
51 static CCS::Thermometer_ptr
52 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 Controller_impl * Thermometer_impl::m_ctrl; // static member
78 // Helper function to read the model string from a device.
80 CCS::ModelType
81 Thermometer_impl::
82 get_model ()
84 char buf[32];
85 assert (ICP_get (m_anum, "model", buf, sizeof (buf)) == 0);
86 return CORBA::string_dup (buf);
89 // Helper function to read the temperature from a device.
91 CCS::TempType
92 Thermometer_impl::
93 get_temp ()
95 short temp;
96 assert (ICP_get (m_anum, "temperature", &temp, sizeof (temp)) == 0);
97 return temp;
100 // Helper function to read the location from a device.
102 CCS::LocType
103 Thermometer_impl::
104 get_loc ()
106 char buf[32];
107 assert (ICP_get (m_anum, "location", buf, sizeof (buf)) == 0);
108 return CORBA::string_dup (buf);
111 // Helper function to set the location of a device.
113 void
114 Thermometer_impl::
115 set_loc (const char * loc)
117 assert (ICP_set (m_anum, "location", loc) == 0);
120 // Constructor.
122 Thermometer_impl::
123 Thermometer_impl (CCS::AssetType anum) : m_anum (anum)
125 m_ctrl->add_impl (anum, this); // Add self to controller's set
128 // Destructor.
130 Thermometer_impl::
131 ~Thermometer_impl ()
133 if (m_ctrl->exists (m_anum))
134 m_ctrl->add_impl (m_anum, 0); // Clear servant pointer
137 // IDL model attribute.
139 CCS::ModelType
140 Thermometer_impl::model ()
142 return get_model ();
145 // IDL asset_num attribute.
147 CCS::AssetType
148 Thermometer_impl::asset_num ()
150 return m_anum;
153 // IDL temperature attribute.
155 CCS::TempType
156 Thermometer_impl::temperature ()
158 return get_temp ();
161 // IDL location attribute accessor.
163 CCS::LocType
164 Thermometer_impl::location ()
166 return get_loc ();
169 // IDL remove operation.
171 void
172 Thermometer_impl::remove ()
174 m_ctrl->remove_impl (m_anum);
175 assert (ICP_offline (m_anum) == 0);
176 // delete this;
179 // IDL location attribute modifier.
181 void
182 Thermometer_impl::location (const char *loc)
184 set_loc (loc);
187 //----------------------------------------------------------------
189 // Helper function to get a thermostat's nominal temperature.
191 CCS::TempType
192 Thermostat_impl::
193 get_nominal_temp ()
195 short temp;
196 assert (ICP_get (m_anum, "nominal_temp", &temp, sizeof (temp)) == 0);
197 return temp;
200 // Helper function to set a thermostat's nominal temperature.
202 CCS::TempType
203 Thermostat_impl::
204 set_nominal_temp (CCS::TempType new_temp)
206 short old_temp;
208 // We need to return the previous nominal temperature,
209 // so we first read the current nominal temperature before
210 // changing it.
211 assert (ICP_get (m_anum, "nominal_temp", &old_temp, sizeof (old_temp)) == 0);
213 // Now set the nominal temperature to the new value.
214 if (ICP_set (m_anum, "nominal_temp", &new_temp) != 0)
216 // If ICP_set () failed, read this thermostat's minimum and
217 // maximum so we can initialize the BadTemp exception.
218 CCS::Thermostat::BtData btd;
219 ICP_get (m_anum, "MIN_TEMP",
220 &btd.min_permitted, sizeof (btd.min_permitted));
221 ICP_get (m_anum, "MAX_TEMP",
222 &btd.max_permitted, sizeof (btd.max_permitted));
223 btd.requested = new_temp;
224 btd.error_msg = CORBA::string_dup (new_temp > btd.max_permitted ? "Too hot" : "Too cold");
225 throw CCS::Thermostat::BadTemp (btd);
227 return old_temp;
230 // Constructor.
232 Thermostat_impl::
233 Thermostat_impl (CCS::AssetType anum) : Thermometer_impl (anum)
235 // Intentionally empty.
238 // Destructor.
240 Thermostat_impl::
241 ~Thermostat_impl ()
243 // Intentionally empty.
246 // IDL get_nominal operation.
248 CCS::TempType
249 Thermostat_impl::get_nominal ()
251 return get_nominal_temp ();
254 // IDL set_nominal operation.
256 CCS::TempType
257 Thermostat_impl::
258 set_nominal (CCS::TempType new_temp)
260 return set_nominal_temp (new_temp);
263 // Helper function to add an entry to the asset map.
265 void
266 Controller_impl::
267 add_impl (CCS::AssetType anum, Thermometer_impl * tip)
269 m_assets[anum] = tip;
272 // Helper function to remove an entry from the asset map.
274 void
275 Controller_impl::
276 remove_impl (CCS::AssetType anum)
278 m_assets.erase (anum);
281 // Helper function to locate a servant in the asset map.
283 bool
284 Controller_impl::
285 exists (CCS::AssetType anum)
287 return m_assets.find (anum) != m_assets.end ();
290 // Constructor
292 Controller_impl::
293 Controller_impl (PortableServer::POA_ptr poa,
294 const char *asset_file)
295 : m_poa (PortableServer::POA::_duplicate (poa)),
296 m_asset_file (asset_file)
298 std::ifstream afile (m_asset_file.in (), std::ios::in|std::ios::out);//, 0666);
299 if (!afile)
301 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
302 throw 0;
304 CCS::AssetType anum;
306 while (afile >> anum)
307 m_assets[anum] = 0;
309 //afile.close ();
310 //if (!afile) {
311 // cerr << "Cannot close " << m_asset_file << endl;
312 // throw 0;
316 // Destructor
318 Controller_impl::
319 ~Controller_impl ()
321 // Write out the current set of asset numbers
322 // and clean up all servant instances.
323 std::ofstream afile (m_asset_file.in ());
324 if (!afile)
326 std::cerr << "Cannot open " << m_asset_file.in () << std::endl;
327 assert (0);
329 AssetMap::iterator i;
331 for (i = m_assets.begin (); i != m_assets.end (); i++)
333 afile << i->first << std::endl;
334 if (!afile)
336 std::cerr << "Cannot update " << m_asset_file.in () << std::endl;
337 assert (0);
339 delete i->second;
341 afile.close ();
342 if (!afile)
344 std::cerr << "Cannot close " << m_asset_file.in () << std::endl;
345 assert (0);
349 CCS::Thermometer_ptr
350 Controller_impl::
351 create_thermometer (CCS::AssetType anum, const char *loc)
353 if (anum % 2 == 0)
354 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
355 if (exists (anum))
356 throw CCS::Controller::DuplicateAsset ();
358 assert (ICP_online (anum) == 0);
359 assert (ICP_set (anum, "location", loc) == 0);
360 add_impl (anum, 0);
361 return make_dref (m_poa.in (), anum);
364 CCS::Thermostat_ptr
365 Controller_impl::
366 create_thermostat (CCS::AssetType anum,
367 const char *loc,
368 CCS::TempType temp)
370 if (anum % 2 != 0)
371 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
372 if (exists (anum))
373 throw CCS::Controller::DuplicateAsset ();
375 assert (ICP_online (anum) == 0);
376 assert (ICP_set (anum, "location", loc) == 0);
377 // Set the nominal temperature.
378 if (ICP_set (anum, "nominal_temp", &temp) != 0)
380 // If ICP_set () failed, read this thermostat's minimum
381 // and maximum so we can initialize the BadTemp exception.
382 CCS::Thermostat::BtData btd;
383 ICP_get (anum, "MIN_TEMP",
384 &btd.min_permitted, sizeof (btd.min_permitted));
385 ICP_get (anum, "MAX_TEMP", &btd.max_permitted, sizeof (btd.max_permitted));
386 btd.requested = temp;
387 btd.error_msg = CORBA::string_dup (temp > btd.max_permitted ? "Too hot" : "Too cold");
388 ICP_offline (anum);
389 throw CCS::Thermostat::BadTemp (btd);
392 add_impl (anum, 0);
393 CORBA::Object_var obj = make_dref (m_poa.in (), anum);
394 return CCS::Thermostat::_narrow (obj.in ());
397 // IDL list operation.
399 CCS::Controller::ThermometerSeq *
400 Controller_impl::list ()
402 // Create a new thermometer sequence. Because we know
403 // the number of elements we will put onto the sequence,
404 // we use the maximum constructor.
405 CCS::Controller::ThermometerSeq_var listv
406 = new CCS::Controller::ThermometerSeq (m_assets.size ());
407 listv->length (m_assets.size ());
409 // Loop over the m_assets set and create a
410 // reference for each device.
411 CORBA::ULong count = 0;
412 AssetMap::iterator i;
414 for (i = m_assets.begin (); i != m_assets.end (); i++)
415 listv[count++] = make_dref (m_poa.in (), i->first);
417 return listv._retn ();
420 // IDL change operation.
422 void
423 Controller_impl::
424 change (const CCS::Controller::ThermostatSeq & tlist,
425 CORBA::Short delta)
427 CCS::Controller::EChange ec; // Just in case we need it
429 // We cannot add a delta value to a thermostat's temperature
430 // directly, so for each thermostat, we read the nominal
431 // temperature, add the delta value to it, and write
432 // it back again.
433 for (CORBA::ULong i = 0; i < tlist.length (); i++)
435 if (CORBA::is_nil (tlist[i]))
436 continue; // Skip nil references
438 // Read nominal temp and update it.
439 CCS::TempType tnom = tlist[i]->get_nominal ();
440 tnom += delta;
443 tlist[i]->set_nominal (tnom);
445 catch (const CCS::Thermostat::BadTemp &bt)
447 // If the update failed because the temperature
448 // is out of range, we add the thermostat's info
449 // to the errors sequence.
450 CORBA::ULong len = ec.errors.length ();
451 ec.errors.length (len + 1);
452 ec.errors[len].tmstat_ref = tlist[i].in ();
453 ec.errors[len].info = bt.details;
457 // If we encountered errors in the above loop, we will have added
458 // elements to the errors sequence.
459 if (ec.errors.length () != 0)
460 throw ec;
463 // IDL find operation
465 void
466 Controller_impl::
467 find (CCS::Controller::SearchSeq & slist)
469 // Loop over input list and lookup each device.
470 CORBA::ULong listlen = slist.length ();
471 for (CORBA::ULong i = 0; i < listlen; i++)
474 AssetMap::iterator where; // Iterator for asset set
475 int num_found = 0; // Num matched per iteration
477 // Assume we will not find a matching device.
478 slist[i].device = CCS::Thermometer::_nil ();
480 // Work out whether we are searching by asset,
481 // model, or location.
482 CCS::Controller::SearchCriterion sc = slist[i].key._d ();
483 if (sc == CCS::Controller::ASSET)
485 // Search for matching asset number.
486 where = m_assets.find (slist[i].key.asset_num ());
487 if (where != m_assets.end ())
488 slist[i].device = make_dref (m_poa.in (), where->first);
490 else
492 // Search for model or location string.
493 const char *search_str;
494 if (sc == CCS::Controller::LOCATION)
495 search_str = slist[i].key.loc ();
496 else
497 search_str = slist[i].key.model_desc ();
499 // Find first matching device (if any).
500 where = find_if (m_assets.begin (), m_assets.end (),
501 StrFinder (sc, search_str));
503 // While there are matches...
504 while (where != m_assets.end ())
506 if (num_found == 0)
508 // First match overwrites reference
509 // in search record.
510 slist[i].device = make_dref (m_poa.in (), where->first);
512 else
514 // Further matches each append a new
515 // element to the search sequence.
516 CORBA::ULong len = slist.length ();
517 slist.length (len + 1);
518 slist[len].key = slist[i].key;
519 slist[len].device = make_dref (m_poa.in (), where->first);
521 num_found++;
523 // Find next matching device with this key.
524 where = find_if (++where, m_assets.end (),
525 StrFinder (sc, search_str));
531 DeviceLocator_impl::
532 DeviceLocator_impl (Controller_impl * ctrl) : m_ctrl (ctrl)
534 // Intentionally empty
537 PortableServer::Servant
538 DeviceLocator_impl::
539 preinvoke (const PortableServer::ObjectId & oid,
540 PortableServer::POA_ptr /*poa*/,
541 const char * operation,
542 void * & /*cookie*/)
544 // Convert object id into asset number.
545 CORBA::String_var oid_string;
548 oid_string = PortableServer::ObjectId_to_string (oid);
550 catch (const CORBA::BAD_PARAM &)
552 throw CORBA::OBJECT_NOT_EXIST ();
555 if (ACE_OS::strcmp (oid_string.in (), Controller_oid) == 0)
556 return m_ctrl;
558 istrstream istr (oid_string.in ());
559 CCS::AssetType anum;
560 istr >> anum;
561 if (istr.fail ())
562 throw CORBA::OBJECT_NOT_EXIST ();
564 // Check whether the device is known.
565 if (!m_ctrl->exists (anum))
566 throw CORBA::OBJECT_NOT_EXIST ();
568 // Look at the object map to find out whether
569 // we have a servant in memory.
570 Thermometer_impl * servant;
571 ActiveObjectMap::iterator servant_pos = m_aom.find (anum);
572 if (servant_pos == m_aom.end ())
574 // No servant in memory. If evictor queue is full,
575 // evict servant at head of queue.
576 if (m_eq.size () == MAX_EQ_SIZE)
578 servant = m_eq.back ();
579 m_aom.erase (servant->m_anum);
580 m_eq.pop_back ();
581 delete servant;
583 // Instantiate correct type of servant.
584 char buf[32];
585 assert (ICP_get (anum, "model", buf, sizeof (buf)) == 0);
586 if (ACE_OS::strcmp (buf, "Sens-A-Temp") == 0)
587 servant = new Thermometer_impl (anum);
588 else
589 servant = new Thermostat_impl (anum);
591 else
593 // Servant already in memory.
594 servant = * (servant_pos->second); // Remember servant
595 m_eq.erase (servant_pos->second); // Remove from queue
597 // If operation is "remove", also remove entry from
598 // active object map -- the object is about to be deleted.
599 if (ACE_OS::strcmp (operation, "remove") == 0)
600 m_aom.erase (servant_pos);
603 // We found a servant, or just instantiated it. If the operation is
604 // not a remove, move the servant to the tail of the evictor queue
605 // and update its queue position in the map.
606 if (ACE_OS::strcmp (operation, "remove") != 0)
608 m_eq.push_front (servant);
609 m_aom[anum] = m_eq.begin ();
612 return servant;
616 ACE_TMAIN(int argc, ACE_TCHAR *argv[])
618 CORBA::ORB_var orb;
622 // Initialize orb
623 orb = CORBA::ORB_init (argc, argv);
625 // Get reference to Root POA.
626 CORBA::Object_var obj
627 = orb->resolve_initial_references ("RootPOA");
628 PortableServer::POA_var poa
629 = PortableServer::POA::_narrow (obj.in ());
631 // Get POA manager
632 PortableServer::POAManager_var poa_mgr = poa->the_POAManager ();
634 // Create a policy list. We use persistent objects with
635 // user-assigned IDs, and explicit activation.
636 CORBA::PolicyList policy_list;
637 policy_list.length (6);
638 policy_list[0] = poa->create_lifespan_policy (PortableServer::TRANSIENT); // REVISIT
639 policy_list[1] = poa->create_id_assignment_policy (PortableServer::USER_ID);
640 policy_list[2] = poa->create_implicit_activation_policy (PortableServer::NO_IMPLICIT_ACTIVATION);
641 policy_list[3] = poa->create_request_processing_policy (PortableServer::USE_SERVANT_MANAGER);
642 policy_list[4] = poa->create_servant_retention_policy (PortableServer::NON_RETAIN);
643 policy_list[5] = poa->create_thread_policy (PortableServer::SINGLE_THREAD_MODEL);
645 // Create a POA for all CCS elements.
646 PortableServer::POA_var ccs_poa
647 = poa->create_POA ("CCS_POA", poa_mgr.in (), policy_list);
649 // Create a controller and set static m_ctrl member
650 // for thermostats and thermometers.
651 Controller_impl ctrl_servant (ccs_poa.in (), "/tmp/CCS_assets");
652 Thermometer_impl::m_ctrl = &ctrl_servant;
654 // Create a reference for the controller and
655 // create the corresponding CORBA object.
656 PortableServer::ObjectId_var oid
657 = PortableServer::string_to_ObjectId (Controller_oid);
658 obj = ccs_poa->create_reference_with_id (oid.in (), "IDL:acme.com/CCS/Controller:1.0");
660 // Write a reference for the controller to stdout.
661 CORBA::String_var str = orb->object_to_string (obj.in ());
662 cout << str.in () << std::endl << std::endl;
664 // Instantiate the servant locator for devices.
665 PortableServer::ServantManager_var locator =
666 new DeviceLocator_impl (&ctrl_servant);
668 // Set servant locator.
669 ccs_poa->set_servant_manager (locator.in ());
671 // Activate the POA manager.
672 poa_mgr->activate ();
674 // Accept requests
675 orb->run ();
677 catch (const CORBA::Exception & e)
679 std::cerr << "Uncaught CORBA exception: "
680 << e
681 << std::endl;
682 return 1;
684 catch (...)
686 assert (0); // Uncaught exception, dump core
688 return 0;