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>
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.
33 operator<< (ostream
& os
, const CORBA::Exception
& e
)
38 CORBA::TypeCode_var tc
= tmp
.type ();
39 const char * p
= tc
->name ();
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.
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 Controller_impl
* Thermometer_impl::m_ctrl
; // static member
78 // Helper function to read the model string from a device.
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.
96 assert (ICP_get (m_anum
, "temperature", &temp
, sizeof (temp
)) == 0);
100 // Helper function to read the location from a device.
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.
115 set_loc (const char * loc
)
117 assert (ICP_set (m_anum
, "location", loc
) == 0);
123 Thermometer_impl (CCS::AssetType anum
) : m_anum (anum
)
125 m_ctrl
->add_impl (anum
, this); // Add self to controller's set
133 if (m_ctrl
->exists (m_anum
))
134 m_ctrl
->add_impl (m_anum
, 0); // Clear servant pointer
137 // IDL model attribute.
140 Thermometer_impl::model ()
145 // IDL asset_num attribute.
148 Thermometer_impl::asset_num ()
153 // IDL temperature attribute.
156 Thermometer_impl::temperature ()
161 // IDL location attribute accessor.
164 Thermometer_impl::location ()
169 // IDL remove operation.
172 Thermometer_impl::remove ()
174 m_ctrl
->remove_impl (m_anum
);
175 assert (ICP_offline (m_anum
) == 0);
179 // IDL location attribute modifier.
182 Thermometer_impl::location (const char *loc
)
187 //----------------------------------------------------------------
189 // Helper function to get a thermostat's nominal temperature.
196 assert (ICP_get (m_anum
, "nominal_temp", &temp
, sizeof (temp
)) == 0);
200 // Helper function to set a thermostat's nominal temperature.
204 set_nominal_temp (CCS::TempType new_temp
)
208 // We need to return the previous nominal temperature,
209 // so we first read the current nominal temperature before
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
);
233 Thermostat_impl (CCS::AssetType anum
) : Thermometer_impl (anum
)
235 // Intentionally empty.
243 // Intentionally empty.
246 // IDL get_nominal operation.
249 Thermostat_impl::get_nominal ()
251 return get_nominal_temp ();
254 // IDL set_nominal operation.
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.
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.
276 remove_impl (CCS::AssetType anum
)
278 m_assets
.erase (anum
);
281 // Helper function to locate a servant in the asset map.
285 exists (CCS::AssetType anum
)
287 return m_assets
.find (anum
) != m_assets
.end ();
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);
301 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
306 while (afile
>> anum
)
311 // cerr << "Cannot close " << m_asset_file << endl;
321 // Write out the current set of asset numbers
322 // and clean up all servant instances.
323 std::ofstream
afile (m_asset_file
.in ());
326 std::cerr
<< "Cannot open " << m_asset_file
.in () << std::endl
;
329 AssetMap::iterator i
;
331 for (i
= m_assets
.begin (); i
!= m_assets
.end (); i
++)
333 afile
<< i
->first
<< std::endl
;
336 std::cerr
<< "Cannot update " << m_asset_file
.in () << std::endl
;
344 std::cerr
<< "Cannot close " << m_asset_file
.in () << std::endl
;
351 create_thermometer (CCS::AssetType anum
, const char *loc
)
354 throw CORBA::BAD_PARAM (); // Thermometers have odd numbers
356 throw CCS::Controller::DuplicateAsset ();
358 assert (ICP_online (anum
) == 0);
359 assert (ICP_set (anum
, "location", loc
) == 0);
361 return make_dref (m_poa
.in (), anum
);
366 create_thermostat (CCS::AssetType anum
,
371 throw CORBA::BAD_PARAM (); // Thermostats have even numbers
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");
389 throw CCS::Thermostat::BadTemp (btd
);
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.
424 change (const CCS::Controller::ThermostatSeq
& tlist
,
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
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 ();
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)
463 // IDL find operation
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
++)
473 AssetMap::iterator where
; // Iterator for asset set
474 int num_found
= 0; // Num matched per iteration
476 // Assume we will not find a matching device.
477 slist
[i
].device
= CCS::Thermometer::_nil ();
479 // Work out whether we are searching by asset,
480 // model, or location.
481 CCS::Controller::SearchCriterion sc
= slist
[i
].key
._d ();
482 if (sc
== CCS::Controller::ASSET
)
484 // Search for matching asset number.
485 where
= m_assets
.find (slist
[i
].key
.asset_num ());
486 if (where
!= m_assets
.end ())
487 slist
[i
].device
= make_dref (m_poa
.in (), where
->first
);
491 // Search for model or location string.
492 const char *search_str
;
493 if (sc
== CCS::Controller::LOCATION
)
494 search_str
= slist
[i
].key
.loc ();
496 search_str
= slist
[i
].key
.model_desc ();
498 // Find first matching device (if any).
499 where
= find_if (m_assets
.begin (), m_assets
.end (),
500 StrFinder (sc
, search_str
));
502 // While there are matches...
503 while (where
!= m_assets
.end ())
507 // First match overwrites reference
509 slist
[i
].device
= make_dref (m_poa
.in (), where
->first
);
513 // Further matches each append a new
514 // element to the search sequence.
515 CORBA::ULong len
= slist
.length ();
516 slist
.length (len
+ 1);
517 slist
[len
].key
= slist
[i
].key
;
518 slist
[len
].device
= make_dref (m_poa
.in (), where
->first
);
522 // Find next matching device with this key.
523 where
= find_if (++where
, m_assets
.end (),
524 StrFinder (sc
, search_str
));
531 DeviceLocator_impl (Controller_impl
* ctrl
) : m_ctrl (ctrl
)
533 // Intentionally empty
536 PortableServer::Servant
538 preinvoke (const PortableServer::ObjectId
& oid
,
539 PortableServer::POA_ptr
/*poa*/,
540 const char * operation
,
543 // Convert object id into asset number.
544 CORBA::String_var oid_string
;
547 oid_string
= PortableServer::ObjectId_to_string (oid
);
549 catch (const CORBA::BAD_PARAM
&)
551 throw CORBA::OBJECT_NOT_EXIST ();
554 if (ACE_OS::strcmp (oid_string
.in (), Controller_oid
) == 0)
557 istrstream
istr (oid_string
.in ());
561 throw CORBA::OBJECT_NOT_EXIST ();
563 // Check whether the device is known.
564 if (!m_ctrl
->exists (anum
))
565 throw CORBA::OBJECT_NOT_EXIST ();
567 // Look at the object map to find out whether
568 // we have a servant in memory.
569 Thermometer_impl
* servant
;
570 ActiveObjectMap::iterator servant_pos
= m_aom
.find (anum
);
571 if (servant_pos
== m_aom
.end ())
573 // No servant in memory. If evictor queue is full,
574 // evict servant at head of queue.
575 if (m_eq
.size () == MAX_EQ_SIZE
)
577 servant
= m_eq
.back ();
578 m_aom
.erase (servant
->m_anum
);
582 // Instantiate correct type of servant.
584 assert (ICP_get (anum
, "model", buf
, sizeof (buf
)) == 0);
585 if (ACE_OS::strcmp (buf
, "Sens-A-Temp") == 0)
586 servant
= new Thermometer_impl (anum
);
588 servant
= new Thermostat_impl (anum
);
592 // Servant already in memory.
593 servant
= * (servant_pos
->second
); // Remember servant
594 m_eq
.erase (servant_pos
->second
); // Remove from queue
596 // If operation is "remove", also remove entry from
597 // active object map -- the object is about to be deleted.
598 if (ACE_OS::strcmp (operation
, "remove") == 0)
599 m_aom
.erase (servant_pos
);
602 // We found a servant, or just instantiated it. If the operation is
603 // not a remove, move the servant to the tail of the evictor queue
604 // and update its queue position in the map.
605 if (ACE_OS::strcmp (operation
, "remove") != 0)
607 m_eq
.push_front (servant
);
608 m_aom
[anum
] = m_eq
.begin ();
615 ACE_TMAIN(int argc
, ACE_TCHAR
*argv
[])
622 orb
= CORBA::ORB_init (argc
, argv
);
624 // Get reference to Root POA.
625 CORBA::Object_var obj
626 = orb
->resolve_initial_references ("RootPOA");
627 PortableServer::POA_var poa
628 = PortableServer::POA::_narrow (obj
.in ());
631 PortableServer::POAManager_var poa_mgr
= poa
->the_POAManager ();
633 // Create a policy list. We use persistent objects with
634 // user-assigned IDs, and explicit activation.
635 CORBA::PolicyList policy_list
;
636 policy_list
.length (6);
637 policy_list
[0] = poa
->create_lifespan_policy (PortableServer::TRANSIENT
); // REVISIT
638 policy_list
[1] = poa
->create_id_assignment_policy (PortableServer::USER_ID
);
639 policy_list
[2] = poa
->create_implicit_activation_policy (PortableServer::NO_IMPLICIT_ACTIVATION
);
640 policy_list
[3] = poa
->create_request_processing_policy (PortableServer::USE_SERVANT_MANAGER
);
641 policy_list
[4] = poa
->create_servant_retention_policy (PortableServer::NON_RETAIN
);
642 policy_list
[5] = poa
->create_thread_policy (PortableServer::SINGLE_THREAD_MODEL
);
644 // Create a POA for all CCS elements.
645 PortableServer::POA_var ccs_poa
646 = poa
->create_POA ("CCS_POA", poa_mgr
.in (), policy_list
);
648 // Create a controller and set static m_ctrl member
649 // for thermostats and thermometers.
650 Controller_impl
ctrl_servant (ccs_poa
.in (), "/tmp/CCS_assets");
651 Thermometer_impl::m_ctrl
= &ctrl_servant
;
653 // Create a reference for the controller and
654 // create the corresponding CORBA object.
655 PortableServer::ObjectId_var oid
656 = PortableServer::string_to_ObjectId (Controller_oid
);
657 obj
= ccs_poa
->create_reference_with_id (oid
.in (), "IDL:acme.com/CCS/Controller:1.0");
659 // Write a reference for the controller to stdout.
660 CORBA::String_var str
= orb
->object_to_string (obj
.in ());
661 cout
<< str
.in () << std::endl
<< std::endl
;
663 // Instantiate the servant locator for devices.
664 PortableServer::ServantManager_var locator
=
665 new DeviceLocator_impl (&ctrl_servant
);
667 // Set servant locator.
668 ccs_poa
->set_servant_manager (locator
.in ());
670 // Activate the POA manager.
671 poa_mgr
->activate ();
676 catch (const CORBA::Exception
& e
)
678 std::cerr
<< "Uncaught CORBA exception: "
685 assert (0); // Uncaught exception, dump core