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) {
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
;
268 &btd
.min_permitted
, sizeof (btd
.min_permitted
)
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
);
286 Thermostat_impl (CCS::AssetType anum
) : Thermometer_impl (anum
)
288 // Intentionally empty.
296 // Intentionally empty.
299 // IDL get_nominal operation.
302 Thermostat_impl::get_nominal ()
304 return get_nominal_temp ();
307 // IDL set_nominal operation.
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.
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.
330 remove_impl (CCS::AssetType anum
)
332 m_assets
.erase (anum
);
335 // Helper function to locate a servant in the asset map.
339 exists (CCS::AssetType anum
)
341 return m_assets
.find (anum
) != m_assets
.end ();
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);
355 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
359 while (afile
>> anum
)
363 // cerr << "Cannot close " << m_asset_file << endl;
373 // Write out the current set of asset numbers
374 // and clean up all servant instances.
375 std::ofstream
afile (m_asset_file
.in ());
377 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
380 AssetMap::iterator i
;
381 for (i
= m_assets
.begin (); i
!= m_assets
.end (); i
++) {
382 afile
<< i
->first
<< std::endl
;
384 std::cerr
<< "Cannot update " << m_asset_file
.in () << std::endl
;
391 // cerr << "Cannot close " << m_asset_file << endl;
397 Controller_impl::create_thermometer (CCS::AssetType anum
, const char * loc
)
400 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
402 throw CCS::Controller::DuplicateAsset ();
404 assert (ICP_online (anum
) == 0);
405 assert (ICP_set (anum
, "location", loc
) == 0);
407 return make_dref (m_poa
.in (), anum
);
418 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
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
;
432 &btd
.min_permitted
, sizeof (btd
.min_permitted
)
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"
443 throw CCS::Thermostat::BadTemp (btd
);
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.
477 const CCS::Controller::ThermostatSeq
& tlist
,
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
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 ();
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)
513 // IDL find operation
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
);
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 ();
542 search_str
= slist
[i
].key
.model_desc ();
544 // Find first matching device (if any).
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
555 slist
[i
].device
= make_dref (m_poa
.in (), where
->first
);
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
);
566 // Find next matching device with this key.
568 ++where
, m_assets
.end (),
569 StrFinder (sc
, search_str
)
576 //----------------------------------------------------------------
579 DeviceLocator_impl (Controller_impl
* ctrl
) : m_ctrl (ctrl
)
581 // Intentionally empty
584 PortableServer::Servant
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
;
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)
603 istrstream
istr (oid_string
.in ());
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
);
626 // Instantiate correct type of servant.
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
);
632 servant
= new Thermostat_impl (anum
);
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 ();
656 //----------------------------------------------------------------
659 ACE_TMAIN(int argc
, ACE_TCHAR
*argv
[])
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 ());
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.
726 n
[0].id
= CORBA::string_dup ("CCS");
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.
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 ();
753 catch (const CORBA::Exception
& e
) {
754 std::cerr
<< "Uncaught CORBA exception: "
760 assert (0); // Uncaught exception, dump core