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
++)
474 AssetMap::iterator where
; // Iterator for asset set
475 int num_found
= 0; // Num matched per iteration
477 // Assume we will not find a matching device.
478 slist
[i
].device
= CCS::Thermometer::_nil ();
480 // Work out whether we are searching by asset,
481 // model, or location.
482 CCS::Controller::SearchCriterion sc
= slist
[i
].key
._d ();
483 if (sc
== CCS::Controller::ASSET
)
485 // Search for matching asset number.
486 where
= m_assets
.find (slist
[i
].key
.asset_num ());
487 if (where
!= m_assets
.end ())
488 slist
[i
].device
= make_dref (m_poa
.in (), where
->first
);
492 // Search for model or location string.
493 const char *search_str
;
494 if (sc
== CCS::Controller::LOCATION
)
495 search_str
= slist
[i
].key
.loc ();
497 search_str
= slist
[i
].key
.model_desc ();
499 // Find first matching device (if any).
500 where
= find_if (m_assets
.begin (), m_assets
.end (),
501 StrFinder (sc
, search_str
));
503 // While there are matches...
504 while (where
!= m_assets
.end ())
508 // First match overwrites reference
510 slist
[i
].device
= make_dref (m_poa
.in (), where
->first
);
514 // Further matches each append a new
515 // element to the search sequence.
516 CORBA::ULong len
= slist
.length ();
517 slist
.length (len
+ 1);
518 slist
[len
].key
= slist
[i
].key
;
519 slist
[len
].device
= make_dref (m_poa
.in (), where
->first
);
523 // Find next matching device with this key.
524 where
= find_if (++where
, m_assets
.end (),
525 StrFinder (sc
, search_str
));
532 DeviceLocator_impl (Controller_impl
* ctrl
) : m_ctrl (ctrl
)
534 // Intentionally empty
537 PortableServer::Servant
539 preinvoke (const PortableServer::ObjectId
& oid
,
540 PortableServer::POA_ptr
/*poa*/,
541 const char * operation
,
544 // Convert object id into asset number.
545 CORBA::String_var oid_string
;
548 oid_string
= PortableServer::ObjectId_to_string (oid
);
550 catch (const CORBA::BAD_PARAM
&)
552 throw CORBA::OBJECT_NOT_EXIST ();
555 if (ACE_OS::strcmp (oid_string
.in (), Controller_oid
) == 0)
558 istrstream
istr (oid_string
.in ());
562 throw CORBA::OBJECT_NOT_EXIST ();
564 // Check whether the device is known.
565 if (!m_ctrl
->exists (anum
))
566 throw CORBA::OBJECT_NOT_EXIST ();
568 // Look at the object map to find out whether
569 // we have a servant in memory.
570 Thermometer_impl
* servant
;
571 ActiveObjectMap::iterator servant_pos
= m_aom
.find (anum
);
572 if (servant_pos
== m_aom
.end ())
574 // No servant in memory. If evictor queue is full,
575 // evict servant at head of queue.
576 if (m_eq
.size () == MAX_EQ_SIZE
)
578 servant
= m_eq
.back ();
579 m_aom
.erase (servant
->m_anum
);
583 // Instantiate correct type of servant.
585 assert (ICP_get (anum
, "model", buf
, sizeof (buf
)) == 0);
586 if (ACE_OS::strcmp (buf
, "Sens-A-Temp") == 0)
587 servant
= new Thermometer_impl (anum
);
589 servant
= new Thermostat_impl (anum
);
593 // Servant already in memory.
594 servant
= * (servant_pos
->second
); // Remember servant
595 m_eq
.erase (servant_pos
->second
); // Remove from queue
597 // If operation is "remove", also remove entry from
598 // active object map -- the object is about to be deleted.
599 if (ACE_OS::strcmp (operation
, "remove") == 0)
600 m_aom
.erase (servant_pos
);
603 // We found a servant, or just instantiated it. If the operation is
604 // not a remove, move the servant to the tail of the evictor queue
605 // and update its queue position in the map.
606 if (ACE_OS::strcmp (operation
, "remove") != 0)
608 m_eq
.push_front (servant
);
609 m_aom
[anum
] = m_eq
.begin ();
616 ACE_TMAIN(int argc
, ACE_TCHAR
*argv
[])
623 orb
= CORBA::ORB_init (argc
, argv
);
625 // Get reference to Root POA.
626 CORBA::Object_var obj
627 = orb
->resolve_initial_references ("RootPOA");
628 PortableServer::POA_var poa
629 = PortableServer::POA::_narrow (obj
.in ());
632 PortableServer::POAManager_var poa_mgr
= poa
->the_POAManager ();
634 // Create a policy list. We use persistent objects with
635 // user-assigned IDs, and explicit activation.
636 CORBA::PolicyList policy_list
;
637 policy_list
.length (6);
638 policy_list
[0] = poa
->create_lifespan_policy (PortableServer::TRANSIENT
); // REVISIT
639 policy_list
[1] = poa
->create_id_assignment_policy (PortableServer::USER_ID
);
640 policy_list
[2] = poa
->create_implicit_activation_policy (PortableServer::NO_IMPLICIT_ACTIVATION
);
641 policy_list
[3] = poa
->create_request_processing_policy (PortableServer::USE_SERVANT_MANAGER
);
642 policy_list
[4] = poa
->create_servant_retention_policy (PortableServer::NON_RETAIN
);
643 policy_list
[5] = poa
->create_thread_policy (PortableServer::SINGLE_THREAD_MODEL
);
645 // Create a POA for all CCS elements.
646 PortableServer::POA_var ccs_poa
647 = poa
->create_POA ("CCS_POA", poa_mgr
.in (), policy_list
);
649 // Create a controller and set static m_ctrl member
650 // for thermostats and thermometers.
651 Controller_impl
ctrl_servant (ccs_poa
.in (), "/tmp/CCS_assets");
652 Thermometer_impl::m_ctrl
= &ctrl_servant
;
654 // Create a reference for the controller and
655 // create the corresponding CORBA object.
656 PortableServer::ObjectId_var oid
657 = PortableServer::string_to_ObjectId (Controller_oid
);
658 obj
= ccs_poa
->create_reference_with_id (oid
.in (), "IDL:acme.com/CCS/Controller:1.0");
660 // Write a reference for the controller to stdout.
661 CORBA::String_var str
= orb
->object_to_string (obj
.in ());
662 cout
<< str
.in () << std::endl
<< std::endl
;
664 // Instantiate the servant locator for devices.
665 PortableServer::ServantManager_var locator
=
666 new DeviceLocator_impl (&ctrl_servant
);
668 // Set servant locator.
669 ccs_poa
->set_servant_manager (locator
.in ());
671 // Activate the POA manager.
672 poa_mgr
->activate ();
677 catch (const CORBA::Exception
& e
)
679 std::cerr
<< "Uncaught CORBA exception: "
686 assert (0); // Uncaught exception, dump core