2 //=============================================================================
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
9 * @author MA.Modified for TAO by Mike Moran <mm4@cs.wustl.edu>
11 //=============================================================================
14 #include <ace/streams.h>
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.
32 operator<< (ostream
& os
, const CORBA::Exception
& e
)
37 CORBA::TypeCode_var tc
= tmp
.type ();
38 const char * p
= tc
->name ();
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.
57 char * anum_str
= ostr
.str ();
58 PortableServer::ObjectId_var oid
59 = PortableServer::string_to_ObjectId (anum_str
);
62 // Look at the model via the network to determine
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.
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.
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.
98 assert (ICP_get (m_anum
, "temperature", &temp
, sizeof (temp
)) == 0);
102 // Helper function to read the location from a device.
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.
117 set_loc (const char * loc
)
119 assert (ICP_set (m_anum
, "location", loc
) == 0);
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
137 assert (ICP_offline (m_anum
) == 0);
141 Thermometer_impl::_add_ref ()
143 ACE_GUARD (ACE_Mutex
, ace_mon
, m_count_mutex
);
148 Thermometer_impl::_remove_ref ()
152 ACE_GUARD (ACE_Mutex
, ace_mon
, m_count_mutex
);
153 if (--m_ref_count
== 0)
160 // IDL model attribute.
163 Thermometer_impl::model ()
168 // IDL asset_num attribute.
171 Thermometer_impl::asset_num ()
176 // IDL temperature attribute.
179 Thermometer_impl::temperature ()
184 // IDL location attribute accessor.
187 Thermometer_impl::location ()
192 // IDL remove operation.
195 Thermometer_impl::remove ()
201 // IDL location attribute modifier.
204 Thermometer_impl::location (const char *loc
)
209 //----------------------------------------------------------------
211 // Helper function to get a thermostat's nominal temperature.
218 assert (ICP_get (m_anum
, "nominal_temp", &temp
, sizeof (temp
)) == 0);
222 // Helper function to set a thermostat's nominal temperature.
225 Thermostat_impl::set_nominal_temp (CCS::TempType new_temp
)
229 // We need to return the previous nominal temperature,
230 // so we first read the current nominal temperature before
234 m_anum
, "nominal_temp", &old_temp
, sizeof (old_temp
)
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
;
245 &btd
.min_permitted
, sizeof (btd
.min_permitted
)
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
);
263 Thermostat_impl (CCS::AssetType anum
) : Thermometer_impl (anum
)
265 // Intentionally empty.
273 // Intentionally empty.
276 // IDL get_nominal operation.
279 Thermostat_impl::get_nominal ()
281 return get_nominal_temp ();
284 // IDL set_nominal operation.
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.
298 add_impl (CCS::AssetType anum
)
300 m_assets
.insert (anum
);
303 // Helper function to remove an entry from the asset map.
307 remove_impl (CCS::AssetType anum
)
309 m_assets
.erase (anum
);
312 // Helper function to locate a servant in the asset map.
315 Controller_impl::exists (CCS::AssetType anum
)
317 return m_assets
.find (anum
) != m_assets
.end ();
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);
329 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
333 while (afile
>> anum
)
334 m_assets
.insert (anum
);
337 // cerr << "Cannot close " << m_asset_file.in () << endl;
347 // Write out the current set of asset numbers
348 // and clean up all servant instances.
349 std::ofstream
afile (m_asset_file
.in ());
351 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
354 AssetSet::iterator i
;
355 for (i
= m_assets
.begin (); i
!= m_assets
.end (); i
++) {
356 afile
<< *i
<< std::endl
;
358 std::cerr
<< "Cannot update " << m_asset_file
.in () << std::endl
;
364 // cerr << "Cannot close " << m_asset_file.in () << endl;
370 Controller_impl::create_thermometer (CCS::AssetType anum
, const char * loc
)
373 ACE_GUARD (ACE_Mutex
, ace_mon
, m_assets_mutex
);
376 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
378 throw CCS::Controller::DuplicateAsset ();
380 assert (ICP_online (anum
) == 0);
381 assert (ICP_set (anum
, "location", loc
) == 0);
385 return make_dref (m_poa
.in (), anum
);
396 ACE_GUARD (ACE_Mutex
, ace_mon
, m_assets_mutex
);
400 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
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
;
413 &btd
.min_permitted
, sizeof (btd
.min_permitted
)
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
);
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 ());
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.
465 const CCS::Controller::ThermostatSeq
& tlist
,
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
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 ();
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)
502 // IDL find operation
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.
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 ()) {
533 slist
[i
].device
= make_dref (m_poa
.in (), num
);
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 ();
540 search_str
= slist
[i
].key
.model_desc ();
542 // Find first matching device (if any).
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
553 slist
[i
].device
= make_dref (m_poa
.in (), *where
);
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
);
564 // Find next matching device with this key.
566 ++where
, m_assets
.end (),
567 StrFinder (sc
, search_str
)
574 //----------------------------------------------------------------
577 DeviceLocator_impl (Controller_impl
* ctrl
) : m_ctrl (ctrl
)
579 // Intentionally empty
582 PortableServer::Servant
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
;
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 ());
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
);
622 servant
->_remove_ref ();
624 // Instantiate correct type of servant.
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
);
630 servant
= new Thermostat_impl (anum
);
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 ();
650 m_ctrl
->remove_impl (anum
);
656 //----------------------------------------------------------------
659 ACE_TMAIN(int argc
, ACE_TCHAR
*argv
[])
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 ());
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 ();
728 catch (const CORBA::Exception
& e
) {
729 std::cerr
<< "Uncaught CORBA exception: "
735 assert (0); // Uncaught exception, dump core