2 //=============================================================================
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
9 * @author MA. Used with permission ofAddison-Wesley.Modified for TAO by Mike Moran <mm4@cs.wustl.edu>
11 //=============================================================================
14 #include <ace/streams.h>
19 #include "orbsvcs/CosNamingC.h"
21 const char * Controller_oid
= "Controller";
22 const unsigned int DeviceLocator_impl::MAX_EQ_SIZE
= 100;
24 //----------------------------------------------------------------
28 resolve_init (CORBA::ORB_ptr orb
, const char * id
)
30 CORBA::Object_var obj
;
32 obj
= orb
->resolve_initial_references (id
);
34 catch (const CORBA::ORB::InvalidName
&) {
37 catch (const CORBA::Exception
& e
) {
38 std::cerr
<< "Cannot get initial reference for "
44 assert (!CORBA::is_nil (obj
.in ()));
46 typename
T::_var_type ref
;
48 ref
= T::_narrow (obj
.in ());
50 catch (const CORBA::Exception
& e
) {
51 std::cerr
<< "Cannot narrow reference for "
57 if (CORBA::is_nil (ref
.in ())) {
58 std::cerr
<< "Incorrect type of reference for "
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.
73 operator<< (ostream
& os
, const CORBA::Exception
& e
)
78 CORBA::TypeCode_var tc
= tmp
.type ();
79 const char * p
= tc
->name ();
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.
99 char * anum_str
= ostr
.str ();
100 PortableServer::ObjectId_var oid
101 = PortableServer::string_to_ObjectId (anum_str
);
104 // Look at the model via the network to determine
105 // the repository ID.
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.
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.
140 assert (ICP_get (m_anum
, "temperature", &temp
, sizeof (temp
)) == 0);
144 // Helper function to read the location from a device.
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.
159 set_loc (const char * loc
)
161 assert (ICP_set (m_anum
, "location", loc
) == 0);
167 Thermometer_impl (CCS::AssetType anum
) : m_anum (anum
)
169 m_ctrl
->add_impl (anum
, this); // Add self to controller's set
177 if (m_ctrl
->exists (m_anum
))
178 m_ctrl
->add_impl (m_anum
, 0); // Clear servant pointer
181 // IDL model attribute.
184 Thermometer_impl::model ()
189 // IDL asset_num attribute.
192 Thermometer_impl::asset_num ()
197 // IDL temperature attribute.
200 Thermometer_impl::temperature ()
205 // IDL location attribute accessor.
208 Thermometer_impl::location ()
213 // IDL remove operation.
216 Thermometer_impl::remove ()
218 m_ctrl
->remove_impl (m_anum
);
219 assert (ICP_offline (m_anum
) == 0);
223 // IDL location attribute modifier.
226 Thermometer_impl::location (const char *loc
)
231 //----------------------------------------------------------------
233 // Helper function to get a thermostat's nominal temperature.
240 assert (ICP_get (m_anum
, "nominal_temp", &temp
, sizeof (temp
)) == 0);
244 // Helper function to set a thermostat's nominal temperature.
247 Thermostat_impl::set_nominal_temp (CCS::TempType new_temp
)
251 // We need to return the previous nominal temperature,
252 // so we first read the current nominal temperature before
256 m_anum
, "nominal_temp", &old_temp
, sizeof (old_temp
)
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
;
267 &btd
.min_permitted
, sizeof (btd
.min_permitted
)
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
);
285 Thermostat_impl (CCS::AssetType anum
) : Thermometer_impl (anum
)
287 // Intentionally empty.
295 // Intentionally empty.
298 // IDL get_nominal operation.
301 Thermostat_impl::get_nominal ()
303 return get_nominal_temp ();
306 // IDL set_nominal operation.
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.
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.
329 remove_impl (CCS::AssetType anum
)
331 m_assets
.erase (anum
);
334 // Helper function to locate a servant in the asset map.
338 exists (CCS::AssetType anum
)
340 return m_assets
.find (anum
) != m_assets
.end ();
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);
354 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
358 while (afile
>> anum
)
362 // cerr << "Cannot close " << m_asset_file << endl;
372 // Write out the current set of asset numbers
373 // and clean up all servant instances.
374 std::ofstream
afile (m_asset_file
.in ());
376 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
379 AssetMap::iterator i
;
380 for (i
= m_assets
.begin (); i
!= m_assets
.end (); i
++) {
381 afile
<< i
->first
<< std::endl
;
383 std::cerr
<< "Cannot update " << m_asset_file
.in () << std::endl
;
390 // cerr << "Cannot close " << m_asset_file << endl;
396 Controller_impl::create_thermometer (CCS::AssetType anum
, const char * loc
)
399 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
401 throw CCS::Controller::DuplicateAsset ();
403 assert (ICP_online (anum
) == 0);
404 assert (ICP_set (anum
, "location", loc
) == 0);
406 return make_dref (m_poa
.in (), anum
);
417 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
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
;
430 &btd
.min_permitted
, sizeof (btd
.min_permitted
)
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"
441 throw CCS::Thermostat::BadTemp (btd
);
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.
475 const CCS::Controller::ThermostatSeq
& tlist
,
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
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 ();
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)
511 // IDL find operation
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
);
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 ();
539 search_str
= slist
[i
].key
.model_desc ();
541 // Find first matching device (if any).
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
552 slist
[i
].device
= make_dref (m_poa
.in (), where
->first
);
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
);
563 // Find next matching device with this key.
565 ++where
, m_assets
.end (),
566 StrFinder (sc
, search_str
)
573 //----------------------------------------------------------------
576 DeviceLocator_impl (Controller_impl
* ctrl
) : m_ctrl (ctrl
)
578 // Intentionally empty
581 PortableServer::Servant
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
;
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)
600 istrstream
istr (oid_string
.in ());
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
);
623 // Instantiate correct type of servant.
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
);
629 servant
= new Thermostat_impl (anum
);
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 ();
653 //----------------------------------------------------------------
656 ACE_TMAIN(int argc
, ACE_TCHAR
*argv
[])
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 ());
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.
723 n
[0].id
= CORBA::string_dup ("CCS");
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.
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 ();
750 catch (const CORBA::Exception
& e
) {
751 std::cerr
<< "Uncaught CORBA exception: "
757 assert (0); // Uncaught exception, dump core