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) {
241 // If ICP_set () failed, read this thermostat's minimum
242 // and maximum so we can initialize the BadTemp exception.
243 CCS::Thermostat::BtData btd
;
246 &btd
.min_permitted
, sizeof (btd
.min_permitted
)
250 &btd
.max_permitted
, sizeof (btd
.max_permitted
)
252 btd
.requested
= new_temp
;
253 btd
.error_msg
= CORBA::string_dup (
254 new_temp
> btd
.max_permitted
? "Too hot" : "Too cold"
256 throw CCS::Thermostat::BadTemp (btd
);
264 Thermostat_impl (CCS::AssetType anum
) : Thermometer_impl (anum
)
266 // Intentionally empty.
274 // Intentionally empty.
277 // IDL get_nominal operation.
280 Thermostat_impl::get_nominal ()
282 return get_nominal_temp ();
285 // IDL set_nominal operation.
288 Thermostat_impl::set_nominal (CCS::TempType new_temp
)
290 return set_nominal_temp (new_temp
);
293 //----------------------------------------------------------------
295 // Helper function to add an entry to the asset map.
299 add_impl (CCS::AssetType anum
)
301 m_assets
.insert (anum
);
304 // Helper function to remove an entry from the asset map.
308 remove_impl (CCS::AssetType anum
)
310 m_assets
.erase (anum
);
313 // Helper function to locate a servant in the asset map.
316 Controller_impl::exists (CCS::AssetType anum
)
318 return m_assets
.find (anum
) != m_assets
.end ();
324 Controller_impl (PortableServer::POA_ptr poa
, const char * asset_file
)
325 : m_poa (PortableServer::POA::_duplicate (poa
)),
326 m_asset_file (asset_file
)
328 std::ifstream
afile (m_asset_file
.in (), std::ios::in
|std::ios::out
);//, 0666);
330 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
334 while (afile
>> anum
)
335 m_assets
.insert (anum
);
338 // cerr << "Cannot close " << m_asset_file.in () << endl;
348 // Write out the current set of asset numbers
349 // and clean up all servant instances.
350 std::ofstream
afile (m_asset_file
.in ());
352 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
355 AssetSet::iterator i
;
356 for (i
= m_assets
.begin (); i
!= m_assets
.end (); i
++) {
357 afile
<< *i
<< std::endl
;
359 std::cerr
<< "Cannot update " << m_asset_file
.in () << std::endl
;
365 // cerr << "Cannot close " << m_asset_file.in () << endl;
371 Controller_impl::create_thermometer (CCS::AssetType anum
, const char * loc
)
374 ACE_GUARD (ACE_Mutex
, ace_mon
, m_assets_mutex
);
377 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
379 throw CCS::Controller::DuplicateAsset ();
381 assert (ICP_online (anum
) == 0);
382 assert (ICP_set (anum
, "location", loc
) == 0);
386 return make_dref (m_poa
.in (), anum
);
397 ACE_GUARD (ACE_Mutex
, ace_mon
, m_assets_mutex
);
401 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
403 throw CCS::Controller::DuplicateAsset ();
405 assert (ICP_online (anum
) == 0);
406 assert (ICP_set (anum
, "location", loc
) == 0);
407 // Set the nominal temperature.
408 if (ICP_set (anum
, "nominal_temp", &temp
) != 0) {
410 // If ICP_set () failed, read this thermostat's minimum
411 // and maximum so we can initialize the BadTemp exception.
412 CCS::Thermostat::BtData btd
;
415 &btd
.min_permitted
, sizeof (btd
.min_permitted
)
419 &btd
.max_permitted
, sizeof (btd
.max_permitted
)
421 btd
.requested
= temp
;
422 btd
.error_msg
= CORBA::string_dup (
423 temp
> btd
.max_permitted
? "Too hot" : "Too cold"
425 throw CCS::Thermostat::BadTemp (btd
);
431 CORBA::Object_var obj
= make_dref (m_poa
.in (), anum
);
432 return CCS::Thermostat::_narrow (obj
.in ());
435 // IDL list operation.
437 CCS::Controller::ThermometerSeq
*
438 Controller_impl::list ()
440 // Create a new thermometer sequence. Because we know
441 // the number of elements we will put onto the sequence,
442 // we use the maximum constructor.
443 CCS::Controller::ThermometerSeq_var listv
444 = new CCS::Controller::ThermometerSeq (m_assets
.size ());
445 listv
->length (m_assets
.size ());
449 ACE_GUARD (ACE_Mutex
, ace_mon
, m_assets_mutex
);
450 tmp_assets
= m_assets
;
453 // Loop over the m_assets set and create a
454 // reference for each device.
455 CORBA::ULong count
= 0;
456 AssetSet::iterator i
;
457 for (i
= tmp_assets
.begin (); i
!= tmp_assets
.end (); i
++)
458 listv
[count
++] = make_dref (m_poa
.in (), *i
);
459 return listv
._retn ();
462 // IDL change operation.
467 const CCS::Controller::ThermostatSeq
& tlist
,
471 CCS::Controller::EChange ec
; // Just in case we need it
473 // We cannot add a delta value to a thermostat's temperature
474 // directly, so for each thermostat, we read the nominal
475 // temperature, add the delta value to it, and write
477 for (CORBA::ULong i
= 0; i
< tlist
.length (); i
++) {
478 if (CORBA::is_nil (tlist
[i
]))
479 continue; // Skip nil references
481 // Read nominal temp and update it.
482 CCS::TempType tnom
= tlist
[i
]->get_nominal ();
485 tlist
[i
]->set_nominal (tnom
);
487 catch (const CCS::Thermostat::BadTemp
&bt
) {
488 // If the update failed because the temperature
489 // is out of range, we add the thermostat's info
490 // to the errors sequence.
491 CORBA::ULong len
= ec
.errors
.length ();
492 ec
.errors
.length (len
+ 1);
493 ec
.errors
[len
].tmstat_ref
= tlist
[i
].in ();
494 ec
.errors
[len
].info
= bt
.details
;
498 // If we encountered errors in the above loop,
499 // we will have added elements to the errors sequence.
500 if (ec
.errors
.length () != 0)
504 // IDL find operation
508 find (CCS::Controller::SearchSeq
& slist
)
510 // Loop over input list and lookup each device.
511 CORBA::ULong listlen
= slist
.length ();
512 for (CORBA::ULong i
= 0; i
< listlen
; i
++) {
514 AssetSet::iterator where
; // Iterator for asset set
515 int num_found
= 0; // Num matched per iteration
517 // Assume we will not find a matching device.
518 slist
[i
].device
= CCS::Thermometer::_nil ();
520 // Work out whether we are searching by asset,
521 // model, or location.
522 CCS::Controller::SearchCriterion sc
= slist
[i
].key
._d ();
523 if (sc
== CCS::Controller::ASSET
) {
524 // Search for matching asset number.
526 CCS::AssetType num
= 0;
528 ACE_GUARD (ACE_Mutex
, ace_mon
, m_assets_mutex
);
529 where
= m_assets
.find (slist
[i
].key
.asset_num ());
530 if (where
!= m_assets
.end ()) {
536 slist
[i
].device
= make_dref (m_poa
.in (), num
);
538 // Search for model or location string.
539 const char *search_str
;
540 if (sc
== CCS::Controller::LOCATION
)
541 search_str
= slist
[i
].key
.loc ();
543 search_str
= slist
[i
].key
.model_desc ();
545 // Find first matching device (if any).
547 m_assets
.begin (), m_assets
.end (),
548 StrFinder (sc
, search_str
)
551 // While there are matches...
552 while (where
!= m_assets
.end ()) {
553 if (num_found
== 0) {
554 // First match overwrites reference
556 slist
[i
].device
= make_dref (m_poa
.in (), *where
);
558 // Further matches each append a new
559 // element to the search sequence.
560 CORBA::ULong len
= slist
.length ();
561 slist
.length (len
+ 1);
562 slist
[len
].key
= slist
[i
].key
;
563 slist
[len
].device
= make_dref (m_poa
.in (), *where
);
567 // Find next matching device with this key.
569 ++where
, m_assets
.end (),
570 StrFinder (sc
, search_str
)
577 //----------------------------------------------------------------
580 DeviceLocator_impl (Controller_impl
* ctrl
) : m_ctrl (ctrl
)
582 // Intentionally empty
585 PortableServer::Servant
588 const PortableServer::ObjectId
& oid
,
589 PortableServer::POA_ptr
/* poa */ ,
590 const char * operation
,
591 void * & /* cookie */
594 // Convert object id into asset number.
595 CORBA::String_var oid_string
;
597 oid_string
= PortableServer::ObjectId_to_string (oid
);
598 } catch (const CORBA::BAD_PARAM
&) {
599 throw CORBA::OBJECT_NOT_EXIST ();
602 istrstream
istr (oid_string
.in ());
606 throw CORBA::OBJECT_NOT_EXIST ();
608 ACE_GUARD (ACE_Mutex
, ace_mon
, m_ctrl
->m_assets_mutex
);
610 // Check whether the device is known.
611 if (!m_ctrl
->exists (anum
))
612 throw CORBA::OBJECT_NOT_EXIST ();
614 // Look at the object map to find out whether
615 // we have a servant in memory.
616 Thermometer_impl
* servant
;
617 ActiveObjectMap::iterator servant_pos
= m_aom
.find (anum
);
618 if (servant_pos
== m_aom
.end ()) {
619 // No servant in memory. If evictor queue is full,
620 // evict servant at head of queue.
621 if (m_eq
.size () == MAX_EQ_SIZE
) {
622 servant
= m_eq
.back ();
623 m_aom
.erase (servant
->m_anum
);
625 servant
->_remove_ref ();
627 // Instantiate correct type of servant.
629 assert (ICP_get (anum
, "model", buf
, sizeof (buf
)) == 0);
630 if (ACE_OS::strcmp (buf
, "Sens-A-Temp") == 0)
631 servant
= new Thermometer_impl (anum
);
633 servant
= new Thermostat_impl (anum
);
635 // Servant already in memory.
636 servant
= * (servant_pos
->second
); // Remember servant
637 m_eq
.erase (servant_pos
->second
); // Remove from queue
639 // If operation is "remove", also remove entry from
640 // active object map -- the object is about to be deleted.
641 if (ACE_OS::strcmp (operation
, "remove") == 0)
642 m_aom
.erase (servant_pos
);
645 // We found a servant, or just instantiated it.
646 // If the operation is not a remove, move
647 // the servant to the tail of the evictor queue
648 // and update its queue position in the map.
649 if (ACE_OS::strcmp (operation
, "remove") != 0) {
650 m_eq
.push_front (servant
);
651 m_aom
[anum
] = m_eq
.begin ();
653 m_ctrl
->remove_impl (anum
);
659 //----------------------------------------------------------------
662 ACE_TMAIN(int argc
, ACE_TCHAR
*argv
[])
666 CORBA::ORB_var orb
= CORBA::ORB_init (argc
, argv
);
668 // Get reference to Root POA.
669 CORBA::Object_var obj
670 = orb
->resolve_initial_references ("RootPOA");
671 PortableServer::POA_var poa
672 = PortableServer::POA::_narrow (obj
.in ());
675 PortableServer::POAManager_var poa_mgr
= poa
->the_POAManager ();
677 // Create a policy list. We use persistent objects with
678 // user-assigned IDs, and explicit activation.
679 CORBA::PolicyList policy_list
;
680 policy_list
.length (3);
681 policy_list
[0] = poa
->create_lifespan_policy (
682 PortableServer::TRANSIENT
// REVISIT
684 policy_list
[1] = poa
->create_id_assignment_policy (
685 PortableServer::USER_ID
687 policy_list
[2] = poa
->create_implicit_activation_policy (
688 PortableServer::NO_IMPLICIT_ACTIVATION
691 // Create a POA for the controller.
692 PortableServer::POA_var ctrl_poa
693 = poa
->create_POA ("CtrlPOA", poa_mgr
.in (), policy_list
);
695 policy_list
.length (5);
696 policy_list
[3] = poa
->create_request_processing_policy (
697 PortableServer::USE_SERVANT_MANAGER
699 policy_list
[4] = poa
->create_servant_retention_policy (
700 PortableServer::NON_RETAIN
703 // Create a POA for the devices.
704 PortableServer::POA_var dev_poa
705 = ctrl_poa
->create_POA ("DevPOA", poa_mgr
.in (), policy_list
);
707 // Create a controller and set static m_ctrl member
708 // for thermostats and thermometers.
709 Controller_impl
ctrl_servant (dev_poa
.in (), "/tmp/CCS_assets");
710 Thermometer_impl::m_ctrl
= &ctrl_servant
;
712 obj
= ctrl_servant
._this ();
714 // Write a reference for the controller to stdout.
715 CORBA::String_var str
= orb
->object_to_string (obj
.in ());
716 std::cout
<< str
.in () << std::endl
<< std::endl
;
718 // Instantiate the servant locator for devices.
719 PortableServer::ServantManager_var locator
=
720 new DeviceLocator_impl (&ctrl_servant
);
722 // Set servant locator.
723 dev_poa
->set_servant_manager (locator
.in ());
725 // Activate the POA manager.
726 poa_mgr
->activate ();
731 catch (const CORBA::Exception
& e
) {
732 std::cerr
<< "Uncaught CORBA exception: "
738 assert (0); // Uncaught exception, dump core