From cfc53c027528e6913576ad03cffcc3cf2fb0cbf6 Mon Sep 17 00:00:00 2001 From: mm4 Date: Tue, 24 Aug 1999 21:35:33 +0000 Subject: Added examples suite from H&V --- TAO/examples/Advanced/README | 48 ++ TAO/examples/Advanced/ch_12/CCS.idl | 104 ++++ TAO/examples/Advanced/ch_12/CHANGES | 84 +++ TAO/examples/Advanced/ch_12/Makefile | 88 +++ TAO/examples/Advanced/ch_12/README | 55 ++ TAO/examples/Advanced/ch_12/client.cpp | 278 +++++++++ TAO/examples/Advanced/ch_12/icp.cpp | 386 +++++++++++++ TAO/examples/Advanced/ch_12/icp.h | 42 ++ TAO/examples/Advanced/ch_12/run_test.pl | 54 ++ TAO/examples/Advanced/ch_12/server.cpp | 732 ++++++++++++++++++++++++ TAO/examples/Advanced/ch_12/server.h | 237 ++++++++ TAO/examples/Advanced/ch_18/CCS.idl | 103 ++++ TAO/examples/Advanced/ch_18/CHANGES | 98 ++++ TAO/examples/Advanced/ch_18/Makefile | 99 ++++ TAO/examples/Advanced/ch_18/README | 45 ++ TAO/examples/Advanced/ch_18/client.cpp | 349 ++++++++++++ TAO/examples/Advanced/ch_18/icp.cpp | 386 +++++++++++++ TAO/examples/Advanced/ch_18/icp.h | 42 ++ TAO/examples/Advanced/ch_18/run_test.pl | 72 +++ TAO/examples/Advanced/ch_18/server.cpp | 791 ++++++++++++++++++++++++++ TAO/examples/Advanced/ch_18/server.h | 238 ++++++++ TAO/examples/Advanced/ch_3/CHANGES | 47 ++ TAO/examples/Advanced/ch_3/Makefile | 71 +++ TAO/examples/Advanced/ch_3/README | 42 ++ TAO/examples/Advanced/ch_3/client.cpp | 67 +++ TAO/examples/Advanced/ch_3/run_test.pl | 54 ++ TAO/examples/Advanced/ch_3/server.cpp | 89 +++ TAO/examples/Advanced/ch_3/server.h | 31 + TAO/examples/Advanced/ch_3/time.idl | 31 + TAO/examples/Advanced/ch_8_and_10/CCS.idl | 88 +++ TAO/examples/Advanced/ch_8_and_10/CHANGES | 51 ++ TAO/examples/Advanced/ch_8_and_10/Makefile | 86 +++ TAO/examples/Advanced/ch_8_and_10/README | 40 ++ TAO/examples/Advanced/ch_8_and_10/client.cpp | 265 +++++++++ TAO/examples/Advanced/ch_8_and_10/icp.cpp | 300 ++++++++++ TAO/examples/Advanced/ch_8_and_10/icp.h | 41 ++ TAO/examples/Advanced/ch_8_and_10/run_test.pl | 54 ++ TAO/examples/Advanced/ch_8_and_10/server.cpp | 464 +++++++++++++++ TAO/examples/Advanced/ch_8_and_10/server.h | 167 ++++++ TAO/examples/Advanced/run_test.pl | 62 ++ 40 files changed, 6381 insertions(+) create mode 100644 TAO/examples/Advanced/README create mode 100644 TAO/examples/Advanced/ch_12/CCS.idl create mode 100644 TAO/examples/Advanced/ch_12/CHANGES create mode 100644 TAO/examples/Advanced/ch_12/Makefile create mode 100644 TAO/examples/Advanced/ch_12/README create mode 100644 TAO/examples/Advanced/ch_12/client.cpp create mode 100644 TAO/examples/Advanced/ch_12/icp.cpp create mode 100644 TAO/examples/Advanced/ch_12/icp.h create mode 100755 TAO/examples/Advanced/ch_12/run_test.pl create mode 100644 TAO/examples/Advanced/ch_12/server.cpp create mode 100644 TAO/examples/Advanced/ch_12/server.h create mode 100644 TAO/examples/Advanced/ch_18/CCS.idl create mode 100644 TAO/examples/Advanced/ch_18/CHANGES create mode 100644 TAO/examples/Advanced/ch_18/Makefile create mode 100644 TAO/examples/Advanced/ch_18/README create mode 100644 TAO/examples/Advanced/ch_18/client.cpp create mode 100644 TAO/examples/Advanced/ch_18/icp.cpp create mode 100644 TAO/examples/Advanced/ch_18/icp.h create mode 100755 TAO/examples/Advanced/ch_18/run_test.pl create mode 100644 TAO/examples/Advanced/ch_18/server.cpp create mode 100644 TAO/examples/Advanced/ch_18/server.h create mode 100644 TAO/examples/Advanced/ch_3/CHANGES create mode 100644 TAO/examples/Advanced/ch_3/Makefile create mode 100644 TAO/examples/Advanced/ch_3/README create mode 100644 TAO/examples/Advanced/ch_3/client.cpp create mode 100755 TAO/examples/Advanced/ch_3/run_test.pl create mode 100644 TAO/examples/Advanced/ch_3/server.cpp create mode 100644 TAO/examples/Advanced/ch_3/server.h create mode 100644 TAO/examples/Advanced/ch_3/time.idl create mode 100644 TAO/examples/Advanced/ch_8_and_10/CCS.idl create mode 100644 TAO/examples/Advanced/ch_8_and_10/CHANGES create mode 100644 TAO/examples/Advanced/ch_8_and_10/Makefile create mode 100644 TAO/examples/Advanced/ch_8_and_10/README create mode 100644 TAO/examples/Advanced/ch_8_and_10/client.cpp create mode 100644 TAO/examples/Advanced/ch_8_and_10/icp.cpp create mode 100644 TAO/examples/Advanced/ch_8_and_10/icp.h create mode 100755 TAO/examples/Advanced/ch_8_and_10/run_test.pl create mode 100644 TAO/examples/Advanced/ch_8_and_10/server.cpp create mode 100644 TAO/examples/Advanced/ch_8_and_10/server.h create mode 100755 TAO/examples/Advanced/run_test.pl diff --git a/TAO/examples/Advanced/README b/TAO/examples/Advanced/README new file mode 100644 index 00000000000..3d191a1c345 --- /dev/null +++ b/TAO/examples/Advanced/README @@ -0,0 +1,48 @@ +$Id$ +______________________________________________________________________________ + +These examples have been taken from the book "Advanced CORBA +Programming with C++" by Michi Henning and Steve Vinoski. Copyright +1999. Addison-Wesley, Reading, MA. To make the examples work with TAO, +some minor modifications to the source code have been made, with +permission, by Mike Moran . Each directory contains a +file CHANGES which describes all modifications, as well as a README file +documenting its use. + +The original source distribution can be found at the Addison-Wesley +homepage: + + + + +The following is the README distibuted with the original code: +______________________________________________________________________________ + + +Each directory contains one of the major code examples of the corresponding +chapter. + +We have not provided Makefiles and a build environment simply because +there are not enough ORBs with a POA around yet to make this feasible. + +You will almost certainly hit minor glitches with include file names. + +Another potential problem is the version of the iostream library supported +by your compiler. The code here uses the old iostream library. If your +compiler requires use of the new ISO/IEC library, you will have to replace +occurences of "#include " with "#include " and +use the std:: qualifier for I/O operations. (The easiest way to deal with +this is probably to add a "using namespace ::std" directive to the +code somewhere. (Similar comments apply to uses of the fstream and strstream +classes.) + +It is also likely that you will encounter some compiler incompatibilities. +If you do and update the source to work for your compiler, please drop +us a note at corba@awl.com. Over time, we hope that with your help, +we can turn the code into something that will work everywhere. + +If you find bugs, we'd appreciate it if you'd let us know. + + Thanks, + + Michi & Steve. \ No newline at end of file diff --git a/TAO/examples/Advanced/ch_12/CCS.idl b/TAO/examples/Advanced/ch_12/CCS.idl new file mode 100644 index 00000000000..44369297576 --- /dev/null +++ b/TAO/examples/Advanced/ch_12/CCS.idl @@ -0,0 +1,104 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_12 +// +// = FILENAME +// CCS.idl +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#pragma prefix "acme.com" + +module CCS { + typedef unsigned long AssetType; + typedef string ModelType; + typedef short TempType; + typedef string LocType; + + interface Thermometer { + readonly attribute ModelType model; + readonly attribute AssetType asset_num; + readonly attribute TempType temperature; + attribute LocType location; + + void remove(); + }; + + interface Thermostat : Thermometer { + struct BtData { + TempType requested; + TempType min_permitted; + TempType max_permitted; + string error_msg; + }; + exception BadTemp { BtData details; }; + + TempType get_nominal(); + TempType set_nominal(in TempType new_temp) + raises(BadTemp); + }; + + interface Controller { + exception DuplicateAsset {}; + + Thermometer create_thermometer( + in AssetType anum, + in LocType loc + ) raises(DuplicateAsset); + Thermostat create_thermostat( + in AssetType anum, + in LocType loc, + in TempType temp + ) raises(DuplicateAsset, Thermostat::BadTemp); + + typedef sequence ThermometerSeq; + typedef sequence ThermostatSeq; + + enum SearchCriterion { ASSET, LOCATION, MODEL }; + + union KeyType switch(SearchCriterion) { + case ASSET: + AssetType asset_num; + case LOCATION: + LocType loc; + case MODEL: + ModelType model_desc; + }; + + struct SearchType { + KeyType key; + Thermometer device; + }; + typedef sequence SearchSeq; + + struct ErrorDetails { + Thermostat tmstat_ref; + Thermostat::BtData info; + }; + typedef sequence ErrSeq; + + exception EChange { + ErrSeq errors; + }; + + ThermometerSeq list(); + void find(inout SearchSeq slist); + void change( + in ThermostatSeq tlist, in short delta + ) raises(EChange); + + }; +}; diff --git a/TAO/examples/Advanced/ch_12/CHANGES b/TAO/examples/Advanced/ch_12/CHANGES new file mode 100644 index 00000000000..4a09d079b18 --- /dev/null +++ b/TAO/examples/Advanced/ch_12/CHANGES @@ -0,0 +1,84 @@ +$Id$ + +Changelog for chapter 8 and 10 example in "Advanced CORBA +Programming with C++" by Michi Henning and Steve Vinoski, +Copyright 1999, Addison-Wesley, Reading, MA. The following +changes have been made to the book's source code to make the +example work with TAO and with various platforms and compilers. + +_______________________________________________________________________________ +ESSENTIAL CHANGES: + 1. Changed filename extensions from .hh and .cc to .h + and .cpp, and made all necessary changes in file content. + + 2. a) Commented-out "#include " in server.h + + b) Added #include "icp.h" to server.h. + + c) Unnecessary standard includes of , , + and must be removed or moved to follow the + local includes in server.h, server.cpp, client.cpp, and icp.cpp. + + d) The following files may need their includes further rearranged + to avoid warnings and errors (g++). The following orderings + seem to work fine: + - server.cpp: "server.h", , "icp.h", + - server.h: "CCSS.h", "icp.h", , + + 3. Added CORBA_Environment variable to + DeviceLocator::preinvoke() and ::postinvoke() + in server.h and server.cpp to match the signatures of parent + methods in TAO's ServanLocator class. + + 4. removed if 0 code surrounding + operator<<(ostream & os, const CCS::Controller::EChange & ec) + definition in server.cpp and client.cpp. + + 5. commented-out "delete this;" from method + Thermometer_impl::remove() in server.cpp. + (Change should soon be reflected in authors' code) +_______________________________________________________________________________ +ADDITIONAL CHANGES: + 6. Added .in() to _var parameters wherever needed: + -client.cpp: + 4 times in operator<<(ostream, CCS::Thermometer_ptr) + 6 times in main(). 5 are is_nil(), 1 is _narrow() + 2 additions in main() of .inout to _var parameters to set_temp(..). + + -server.cpp, + 2 changes in make_dref() + 2 changes in Controller_impl::Controller_impl() + 4 changes in Controller_impl::~Controller_impl() + 1 change in Controller_impl::create_thermometer + 2 changes in Controller_impl::create_thermostat() + 1 change in Controller_impl::list() + 3 changes in Controller_impl::find + 7 changes in main() + + 7. created needed file at /tmp/CCS_DB. (location is hard-coded) + To run, move CCS_DB from this directory to /tmp on the + local machine. + + 8. fixed warnings by commented out unused parameters in + -DeviceLocator_impl::postinvoke(..) in server.h + -DeviceLocator_impl::preinvoke(..) in server.cpp + + 9. MAX_EQ_SIZE changed from int to unsigned int + in class DeviceLocator_impl in server.h. + + 10. added cast to unsigned long in ~ICP_Persist() in icp.cpp: + db << (unsigned long)(i->second.type) << endl; + + +______________________________________________________________________________ +To Do: + - fix error on 2 cases of fstream.close() + in server.cpp and icp.cpp + + + + + + + + diff --git a/TAO/examples/Advanced/ch_12/Makefile b/TAO/examples/Advanced/ch_12/Makefile new file mode 100644 index 00000000000..793da932839 --- /dev/null +++ b/TAO/examples/Advanced/ch_12/Makefile @@ -0,0 +1,88 @@ +#---------------------------------------------------------------------------- +# +# $Id$ +# +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +ifndef TAO_ROOT + TAO_ROOT = $(ACE_ROOT)/TAO +endif + +LDLIBS = -lTAO +IDL_SRC = CCSC.cpp CCSS.cpp +IDL_HDR = CCSC.h CCSS.h + +PROG_SRCS = \ + client.cpp \ + server.cpp \ + icp.cpp + +SRC = $(IDL_SRC) $(PROG_SRCS) + +SIMPLE_CLT_OBJS = \ + CCSC.o \ + CCSS.o \ + client.o + +SIMPLE_SVR_OBJS = \ + CCSC.o \ + CCSS.o \ + server.o \ + icp.o + + +BIN = server \ + client +BUILD = $(BIN) +VLDLIBS = $(LDLIBS:%=%$(VAR)) +VBIN = $(BIN:%=%$(VAR)) + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(ACE_ROOT)/include/makeinclude/macros.GNU +include $(TAO_ROOT)/rules.tao.GNU +include $(ACE_ROOT)/include/makeinclude/rules.common.GNU +include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU +include $(ACE_ROOT)/include/makeinclude/rules.local.GNU +include $(TAO_ROOT)/taoconfig.mk + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- +LDFLAGS += -L$(TAO_ROOT)/orbsvcs/orbsvcs -L$(TAO_ROOT)/tao -L$(TAO_ROOT)/orbsvcs/Naming_Service +CPPFLAGS += -I$(TAO_ROOT)/orbsvcs + +.PRECIOUS: CCSC.cpp CCSC.i CCSC.h +.PRECIOUS: CCSS.cpp CCSS.i CCSS.h +.PRECIOUS: CCSS_T.cpp CCSS_T.i CCSS_T.h + +override TAO_IDLFLAGS += -hc .hh -hs S.hh -hT S_T.hh \ + -cs C.cc -ci C.i \ + -ss S.cc -sT S_T.cc +CCFLAGS += -fimplicit-templates -frtti -O0 + +$(IDL_SRC): CCS.idl + $(TAO_ROOT)/TAO_IDL/tao_idl CCS.idl -hc .h -hs S.h -hT S_T.h \ + -cs C.cpp \ + -ss S.cpp -sT S_T.cpp +server: $(addprefix $(VDIR),$(SIMPLE_SVR_OBJS)) + $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS) $(POSTLINK) + +client: $(addprefix $(VDIR),$(SIMPLE_CLT_OBJS)) + $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS) $(POSTLINK) + +realclean: clean + -/bin/$(RM) -rf CCSC.* CCSS.* CCSS_T.* CCS.h + +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + + + diff --git a/TAO/examples/Advanced/ch_12/README b/TAO/examples/Advanced/ch_12/README new file mode 100644 index 00000000000..d099fbc905c --- /dev/null +++ b/TAO/examples/Advanced/ch_12/README @@ -0,0 +1,55 @@ +$Id$ + +Chapter 12 example. +______________________________________________________________________________ +This example been taken from the book "Advanced CORBA Programming with C++" +by Michi Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +MA. To make the examples work with TAO, some minor modifications to the +source code have been made, with permission, by Mike Moran . +All of these changes are documented in the file CHANGES, in this directory. +______________________________________________________________________________ + + +Summary: + This example builds on the climate control system presented in chapters 8 + and 10. The added use of customized POA policies including the use of a + servant manager is discussed in chapter 11. The example also incorporates + a simulated ICP network within the server process with code from Appendix + A. The simulated network loads it's devices from + +Building: + This example must be built with native C++ exceptions, and with an ACE/TAO + build with exceptions. Make sure to use TAO_FLAG Ge=0 to ensure that the + IDL generated code uses c++ exceptions rather than creating + CORBA_Environment variables. + + With GNU make, simply type + % make exceptions=1 + to create the executable server and client + +server: + The server takes no parameters nor command line options and returns an + IOR to stdout. The server then waits infinitely for clients requests. + +client: + The client takes an IOR from the command line, narrows this to a + controller reference, makes several remote calls on this controller, and + finally terminates. + +run_test.pl: + This is currently a UNIX only script! It starts up the server, redirecting + stdout to a file, then passes the file's contents to the command line of + the client. After the client terminates, the server is killed. + + + + + + + + + + + + + diff --git a/TAO/examples/Advanced/ch_12/client.cpp b/TAO/examples/Advanced/ch_12/client.cpp new file mode 100644 index 00000000000..c30133c5f87 --- /dev/null +++ b/TAO/examples/Advanced/ch_12/client.cpp @@ -0,0 +1,278 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_12 +// +// = FILENAME +// client.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + + +#include "CCS.h" // ORB-specific +// #include +// #include + +//---------------------------------------------------------------- + +// Generic ostream inserter for exceptions. Inserts the exception +// name, if available, and the repository ID otherwise. + +//#if 0 // This inserter may or may not be needed for your ORB. + +static ostream & +operator<<(ostream & os, const CORBA::Exception & e) +{ + CORBA::Any tmp; + tmp <<= e; + + CORBA::TypeCode_var tc = tmp.type(); + const char * p = tc->name(); + if (*p != '\0') + os << p; + else + os << tc->id(); + return os; +} + +//#endif + +//---------------------------------------------------------------- + +// Show the details for a thermometer or thermostat. + +static ostream & +operator<<(ostream &os, CCS::Thermometer_ptr t) +{ + // Check for nil. + if (CORBA::is_nil(t)) { + os << "Cannot show state for nil reference." << endl; + return os; + } + + // Try to narrow and print what kind of device it is. + CCS::Thermostat_var tmstat = CCS::Thermostat::_narrow(t); + os << (CORBA::is_nil(tmstat.in()) ? "Thermometer:" : "Thermostat:") + << endl; + + // Show attribute values. + CCS::ModelType_var model = t->model(); + CCS::LocType_var location = t->location(); + os << "\tAsset number: " << t->asset_num() << endl; + os << "\tModel : " << model.in() << endl; + os << "\tLocation : " << location.in() << endl; + os << "\tTemperature : " << t->temperature() << endl; + + // If device is a thermostat, show nominal temperature. + if (!CORBA::is_nil(tmstat.in())) + os << "\tNominal temp: " << tmstat->get_nominal() << endl; + return os; +} + +//---------------------------------------------------------------- + +// Show the information in a BtData struct. + +static ostream & +operator<<(ostream &os, const CCS::Thermostat::BtData &btd) +{ + os << "CCS::Thermostat::BtData details:" << endl; + os << "\trequested : " << btd.requested << endl; + os << "\tmin_permitted: " << btd.min_permitted << endl; + os << "\tmax_permitted: " << btd.max_permitted << endl; + os << "\terror_msg : " << btd.error_msg << endl; + return os; +} + +//---------------------------------------------------------------- + +// Loop over the sequence of records in an EChange exception and +// show the details of each record. + +static ostream & +operator<<(ostream &os, const CCS::Controller::EChange &ec) +{ + for (CORBA::ULong i = 0; i < ec.errors.length(); i++) { + os << "Change failed:" << endl; + os << ec.errors[i].tmstat_ref.in(); // Overloaded << + os << ec.errors[i].info << endl; // Overloaded << + } + return os; +} + +//---------------------------------------------------------------- + +// Change the temperature of a thermostat. + +static void +set_temp(CCS::Thermostat_ptr tmstat, CCS::TempType new_temp) +{ + if (CORBA::is_nil(tmstat)) // Don't call via nil reference + return; + + CCS::AssetType anum = tmstat->asset_num(); + try { + cout << "Setting thermostat " << anum + << " to " << new_temp << " degrees." << endl; + CCS::TempType old_nominal = tmstat->set_nominal(new_temp); + cout << "Old nominal temperature was: " + << old_nominal << endl; + cout << "New nominal temperature is: " + << tmstat->get_nominal() << endl; + } catch (const CCS::Thermostat::BadTemp &bt) { + cerr << "Setting of nominal temperature failed." << endl; + cerr << bt.details << endl; // Overloaded << + } +} + +//---------------------------------------------------------------- + +int +main(int argc, char * argv[]) +{ + try { + // Initialize the ORB + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + // Check arguments + if (argc != 2) { + cerr << "Usage: client IOR_string" << endl; + throw 0; + } + + // Get controller reference from argv + // and convert to object. + CORBA::Object_var obj = orb->string_to_object(argv[1]); + if (CORBA::is_nil(obj.in())) { + cerr << "Nil controller reference" << endl; + throw 0; + } + + // Try to narrow to CCS::Controller. + CCS::Controller_var ctrl; + try { + ctrl = CCS::Controller::_narrow(obj.in()); + } catch (const CORBA::SystemException &se) { + cerr << "Cannot narrow controller reference: " + << se << endl; + throw 0; + } + if (CORBA::is_nil(ctrl.in())) { + cerr << "Wrong type for controller ref." << endl; + throw 0; + } + + // Get list of devices + CCS::Controller::ThermometerSeq_var list = ctrl->list(); + + // Show number of devices. + CORBA::ULong len = list->length(); + cout << "Controller has " << len << " device"; + if (len != 1) + cout << "s"; + cout << "." << endl; + + CCS::Thermometer_var t = ctrl->create_thermometer(27, "Room 1"); + CCS::Thermostat_var ts = ctrl->create_thermostat(28, "Room 2", 48); + CCS::Thermostat_var ts2 = ctrl->create_thermostat(30, "Room 3", 48); + CCS::Thermostat_var ts3 = ctrl->create_thermostat(32, "Room 3", 68); + CCS::Thermostat_var ts4 = ctrl->create_thermostat(34, "Room 3", 68); + CCS::Thermostat_var ts5 = ctrl->create_thermostat(36, "Room 3", 48); + cout << t->location() << endl; + cout << ts->location() << endl; + cout << ts2->location() << endl; + t->remove(); + + list = ctrl->list(); + // Show details for each device. + for (CORBA::ULong i = 0; i < list->length(); i++) + cout << list[i]; + cout << endl; + + // Change the location of first device in the list + CCS::AssetType anum = list[0]->asset_num(); + cout << "Changing location of device " + << anum << "." << endl; + list[0]->location("Earth"); + // Check that the location was updated + cout << "New details for device " + << anum << " are:" << endl; + cout << list[0] << endl; + + // Find first thermostat in list. + CCS::Thermostat_var tmstat; + for ( CORBA::ULong i = 0; + i < list->length() && CORBA::is_nil(tmstat.in()); + i++) { + tmstat = CCS::Thermostat::_narrow(list[i]); + } + + // Check that we found a thermostat on the list. + if (CORBA::is_nil(tmstat.in())) { + cout << "No thermostat devices in list." << endl; + } else { + // Set temperature of thermostat to + // 50 degrees (should work). + set_temp(tmstat.inout(), 50); + cout << endl; + + // Set temperature of thermostat to + // -10 degrees (should fail). + set_temp(tmstat.inout(), -10); + } + + // Look for device in Rooms Earth and HAL. This must + // locate at least one device because we earlier changed + // the location of the first device to Room Earth. + cout << "Looking for devices in Earth and HAL." << endl; + CCS::Controller::SearchSeq ss; + ss.length(2); + ss[0].key.loc(CORBA::string_dup("Earth")); + ss[1].key.loc(CORBA::string_dup("HAL")); + ctrl->find(ss); + + // Show the devices found in that room. + for (CORBA::ULong i = 0; i < ss.length(); i++) + cout << ss[i].device.in(); // Overloaded << + cout << endl; + + // Increase the temperature of all thermostats + // by 40 degrees. First, make a new list (tss) + // containing only thermostats. + cout << "Increasing thermostats by 40 degrees." << endl; + CCS::Controller::ThermostatSeq tss; + for (CORBA::ULong i = 0; i < list->length(); i++) { + tmstat = CCS::Thermostat::_narrow(list[i]); + if (CORBA::is_nil(tmstat.in())) + continue; // Skip thermometers + len = tss.length(); + tss.length(len + 1); + tss[len] = tmstat; + } + + // Try to change all thermostats. + try { + ctrl->change(tss, 40); + } catch (const CCS::Controller::EChange &ec) { + cerr << ec; // Overloaded << + } + } catch (const CORBA::Exception & e) { + cerr << "Uncaught CORBA exception: " << e << endl; + return 1; + } catch (...) { + return 1; + } + return 0; +} diff --git a/TAO/examples/Advanced/ch_12/icp.cpp b/TAO/examples/Advanced/ch_12/icp.cpp new file mode 100644 index 00000000000..deac39c9248 --- /dev/null +++ b/TAO/examples/Advanced/ch_12/icp.cpp @@ -0,0 +1,386 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_12 +// +// = FILENAME +// icp.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#include +#include +#include +#include "icp.h" +//#include +//---------------------------------------------------------------- + +enum DeviceType { thermometer, thermostat }; + +struct DeviceState { // State for a device + DeviceType type; + const char * model; + string location; + short nominal_temp; // For thermostats only +}; +typedef map StateMap; + +//---------------------------------------------------------------- + +const size_t MAXSTR = 32; // Max len of string including NUL + +const short MIN_TEMP = 40; // 40 F == 4.44 C +const short MAX_TEMP = 90; // 90 F == 32.22 C +const short DFLT_TEMP = 68; // 68 F == 20.00 C + +static StateMap dstate; // Map of known devices + +//---------------------------------------------------------------- + +// ICP_online() simulates adding a new device to the network by +// adding it to the dstate map. +// +// For this simple simulation, devices with odd asset numbers +// are thermometers and devices with even asset numbers +// are thermostats. +// +// Thermostats get an initial nominal temperature of DFLT_TEMP. +// The location string is intentionally left blank because it +// must be programmed by the controller after putting the device +// on-line (as should be the nominal temperature). +// +// If a device with the specified ID is already on-line, the +// return value is -1. A zero return value indicates success. + +extern "C" +int +ICP_online(unsigned long id) +{ + // Look for id in state map. + StateMap::iterator pos = dstate.find(id); + if (pos != dstate.end()) + return -1; // Already exists + + // Fill in state. + DeviceState ds; + ds.type = (id % 2) ? thermometer : thermostat; + ds.model = (ds.type == thermometer) + ? "Sens-A-Temp" : "Select-A-Temp"; + ds.nominal_temp = DFLT_TEMP; + + // Insert new device into map + dstate[id] = ds; + + return 0; +} + +//---------------------------------------------------------------- + +// ICP_offline() simulates removing a device from the network by +// removing it from the dstate map. If the device isn't known, the +// return value is -1. A zero return value indicates success. + +extern "C" +int +ICP_offline(unsigned long id) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + dstate.erase(id); + return 0; +} + +//---------------------------------------------------------------- + +// vary_temp() simulates the variation in actual temperature +// around a thermostat.The function randomly varies the +// temperature as a percentage of calls as follows: +// +// 3 degrees too cold: 5% +// 3 degrees too hot: 5% +// 2 degrees too cold: 10% +// 2 degrees too hot: 10% +// 1 degree too cold: 15% +// 1 degree too hot: 15% +// exact temperature: 40% + +static +short +vary_temp(short temp) +{ + long r = lrand48() % 50; + long delta; + if (r < 5) + delta = 3; + else if (r < 15) + delta = 2; + else if (r < 30) + delta = 1; + else + delta = 0; + if (lrand48() % 2) + delta = -delta; + return temp + delta; +} + +//---------------------------------------------------------------- + +// Function object. Locates a thermostat that is in the same room +// as the device at position pos. + +class ThermostatInSameRoom { +public: + ThermostatInSameRoom( + const StateMap::iterator & pos + ) : m_pos(pos) {} + bool operator()( + pair & p + ) const + { + return( + p.second.type == thermostat + && p.second.location + == m_pos->second.location + ); + } +private: + const StateMap::iterator & m_pos; +}; + +//---------------------------------------------------------------- + +// actual_temp() is a helper function to determine the actual +// temperature returned by a particular thermometer or thermostat. +// The pos argument indicates the device. +// +// The function locates all thermostats that are in the same room +// as the device denoted by pos and computes the average of all +// the thermostats' nominal temperatures. (If no thermostats are +// in the same room as the device, the function assumes that the +// average of the nominal temperatures is DFLT_TEMP.) +// +// The returned temperature varies from the average as +// determined by vary_temp(). + +static +short +actual_temp(const StateMap::iterator & pos) +{ + long sum = 0; + long count = 0; + StateMap::iterator where = find_if( + dstate.begin(), dstate.end(), + ThermostatInSameRoom(pos) + ); + while (where != dstate.end()) { + count++; + sum += where->second.nominal_temp; + where = find_if( + ++where, dstate.end(), + ThermostatInSameRoom(pos) + ); + } + return vary_temp(count == 0 ? DFLT_TEMP : sum / count); +} + +//---------------------------------------------------------------- + +// ICP_get() returns an attribute value of the device with the +// given id. The attribute is named by the attr parameter. The +// value is copied into the buffer pointed to by the value +// pointer. The len parameter is the size of the passed buffer, +// so ICP_get can avoid overrunning the buffer. +// +// By default, thermometers report a temperature that varies +// somewhat around DFLT_TEMP. However, if there is another +// thermostat in the same room as the the thermometer, the +// thermometer reports a temperature that varies around that +// thermostat's temperature. For several thermostats that are in +// the same room, the thermometer reports around the average +// nominal temperature of all the thermostats. +// +// Attempts to read from a non-existent device or to read a +// non-existent attribute return -1. A return value of zero +// indicates success. If the supplied buffer is too short to hold +// a value, ICP_get() silently truncates the value and +// returns success. + +extern "C" +int +ICP_get( + unsigned long id, + const char * attr, + void * value, + size_t len) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + + // Depending on the attribute, return the + // corresponding piece of state. + if (strcmp(attr, "model") == 0) { + strncpy((char *)value, pos->second.model, len); + } else if (strcmp(attr, "location") == 0) { + strncpy((char *)value, pos->second.location.c_str(), len); + } else if (strcmp(attr, "nominal_temp") == 0) { + if (pos->second.type != thermostat) + return -1; // Must be thermostat + memcpy( + value, &pos->second.nominal_temp, + min(len, sizeof(pos->second.nominal_temp)) + ); + } else if (strcmp(attr, "temperature") == 0) { + short temp = actual_temp(pos); + memcpy(value, &temp, min(len, sizeof(temp))); + } else if (strcmp(attr, "MIN_TEMP") == 0) { + memcpy(value, &MIN_TEMP, min(len, sizeof(MIN_TEMP))); + } else if (strcmp(attr, "MAX_TEMP") == 0) { + memcpy(value, &MAX_TEMP, min(len, sizeof(MAX_TEMP))); + } else { + return -1; // No such attribute + } + return 0; // OK +} + +//---------------------------------------------------------------- + +// ICP_set() sets the the attributed specified by attr to the +// value specified by value for the device with ID id. Attempts to +// write a string longer than MAXSTR bytes (including the +// terminating NUL) result in silent truncation of the string. +// Attempts to access a non-existent device or attribute +// return -1. Attempts to set a nominal temperature outside the +// legal range also return -1. A zero return value +// indicates success. + +extern "C" +int +ICP_set(unsigned long id, const char * attr, const void * value) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + + // Change either location or nominal temp, depending on attr. + if (strcmp(attr, "location") == 0) { + pos->second.location.assign( + (const char *)value, MAXSTR - 1 + ); + } else if (strcmp(attr, "nominal_temp") == 0) { + if (pos->second.type != thermostat) + return -1; // Must be thermostat + short temp; + memcpy(&temp, value, sizeof(temp)); + if (temp < MIN_TEMP || temp > MAX_TEMP) + return -1; + pos->second.nominal_temp = temp; + } else { + return -1; // No such attribute + } + return 0; // OK +} + +//---------------------------------------------------------------- + +#include + +class ICP_Persist { +public: + ICP_Persist(const char * file); + ~ICP_Persist(); +private: + string m_filename; +}; + +// Read device state from a file and initialize the dstate map. + +ICP_Persist:: +ICP_Persist(const char * file) : m_filename(file) +{ + // Open input file, creating it if necessary. + fstream db(m_filename.c_str(), ios::in|ios::out, 0666); + if (!db) { + cerr << "Error opening " << m_filename << endl; + exit(1); + } + + // Read device details, one attribute per line. + DeviceState ds; + unsigned long id; + while (db >> id) { + // Read device type and set model string accordingly. + int dtype; + db >> dtype; + ds.type = dtype == thermometer + ? thermometer : thermostat; + ds.model = dtype == thermometer + ? "Sens-A-Temp" : "Select-A-Temp"; + char loc[MAXSTR]; + db.get(loc[0]); // Skip newline + db.getline(loc, sizeof(loc)); // Read location + ds.location = loc; + if (ds.type == thermostat) + db >> ds.nominal_temp; // Read temperature + dstate[id] = ds; // Add entry to map + } + + //db.close(); + //if (!db) { + // cerr << "Error closing " << m_filename << endl; + // exit(1); + //} +} + +// Write device state to the file. + +ICP_Persist:: +~ICP_Persist() +{ + cout<<"~ICP_Persist"<first << endl; + db << (unsigned long)(i->second.type) << endl; + db << i->second.location << endl; + if (i->second.type == thermostat) + db << i->second.nominal_temp << endl; + } + if (!db) { + cerr << "Error writing " << m_filename << endl; + exit(1); + } + + db.close(); + if (!db) { + cerr << "Error closing " << m_filename << endl; + exit(1); + } +} + +// Instantiate a single global instance of the class. +static ICP_Persist mydb("/tmp/CCS_DB"); diff --git a/TAO/examples/Advanced/ch_12/icp.h b/TAO/examples/Advanced/ch_12/icp.h new file mode 100644 index 00000000000..a64ec00f28e --- /dev/null +++ b/TAO/examples/Advanced/ch_12/icp.h @@ -0,0 +1,42 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_12 +// +// = FILENAME +// icp.h +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#ifndef _ICP_H +#define _ICP_H + +extern "C" { + int ICP_online(unsigned long id); // Add device + int ICP_offline(unsigned long id); // Remove device + int ICP_get( // Get attribute + unsigned long id, + const char * attr, + void * value, + size_t len + ); + int ICP_set( // Set attribute + unsigned long id, + const char * attr, + const void * value + ); +} + +#endif /* _ICP_H */ diff --git a/TAO/examples/Advanced/ch_12/run_test.pl b/TAO/examples/Advanced/ch_12/run_test.pl new file mode 100755 index 00000000000..74c52a910be --- /dev/null +++ b/TAO/examples/Advanced/ch_12/run_test.pl @@ -0,0 +1,54 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "../../../../bin"; + +require ACEutils; +require Process; + +$status = 0; +$iorfile = "chapter_test.ior"; +unlink $iorfile; + + + +# Hacked call +$server = Process::Create ("exec ".$EXEPREFIX."server".$EXE_EXT.">$iorfile", + ""); +# Proper call +#$server = Process::Create ($EXEPREFIX."server".$EXE_EXT, ">$iorfile"); + +if (ACE::waitforfile_timed ($iorfile, 15) == -1) { + print STDERR "ERROR: timedout waiting for file <$iorfile>\n"; + $server->Kill (); $server->TimedWait (1); + exit 1; +} + +open(ior_handle, "$iorfile"); +$ior_content = ; + +$client = Process::Create($EXEPREFIX."client$EXE_EXT", "$ior_content"); + +if ($client->TimedWait (60) == -1) { + print STDERR "ERROR: client timedout\n"; + $status = 1; + $client->Kill (); $client->TimedWait (1); +} + + + + +$server->Terminate (); +if ($server->TimedWait (5) == -1) { + print STDERR "ERROR: cannot terminate the server\n"; + $server->Kill (); $server->TimedWait (1); + $status = 1; +} + +unlink $iorfile; + +exit $status; diff --git a/TAO/examples/Advanced/ch_12/server.cpp b/TAO/examples/Advanced/ch_12/server.cpp new file mode 100644 index 00000000000..f70e98dea1d --- /dev/null +++ b/TAO/examples/Advanced/ch_12/server.cpp @@ -0,0 +1,732 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_12 +// +// = FILENAME +// server.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#include "server.h" +#include +#include "icp.h" +#include +// #include +// #include + +const char * Controller_oid = "Controller"; + +//---------------------------------------------------------------- + +// Generic ostream inserter for exceptions. Inserts the exception +// name, if available, and the repository ID otherwise. + +//#if 0 // This inserter may or may not be needed for your ORB. + +static ostream & +operator<<(ostream & os, const CORBA::Exception & e) +{ + CORBA::Any tmp; + tmp <<= e; + + CORBA::TypeCode_var tc = tmp.type(); + const char * p = tc->name(); + if (*p != '\0') + os << p; + else + os << tc->id(); + return os; +} + +//#endif + +//---------------------------------------------------------------- + +// Helper function to create object references. + +static CCS::Thermometer_ptr +make_dref(PortableServer::POA_ptr poa, CCS::AssetType anum) +{ + // Convert asset number to OID. + ostrstream ostr; + ostr << anum << ends; + char * anum_str = ostr.str(); + PortableServer::ObjectId_var oid + = PortableServer::string_to_ObjectId(anum_str); + delete[] anum_str; + + // Look at the model via the network to determine + // the repository ID. + char buf[32]; + assert(ICP_get(anum, "model", buf, sizeof(buf)) == 0); + const char * rep_id = strcmp(buf, "Sens-A-Temp") == 0 + ? "IDL:acme.com/CCS/Thermometer:1.0" + : "IDL:acme.com/CCS/Thermostat:1.0"; + + // Make a new reference. + CORBA::Object_var obj + = poa->create_reference_with_id(oid.in(), rep_id); + return CCS::Thermometer::_narrow(obj.in()); +} + +//---------------------------------------------------------------- + +Controller_impl * Thermometer_impl::m_ctrl; // static member + +// Helper function to read the model string from a device. + +CCS::ModelType +Thermometer_impl:: +get_model() +{ + char buf[32]; + assert(ICP_get(m_anum, "model", buf, sizeof(buf)) == 0); + return CORBA::string_dup(buf); +} + +// Helper function to read the temperature from a device. + +CCS::TempType +Thermometer_impl:: +get_temp() +{ + short temp; + assert(ICP_get(m_anum, "temperature", &temp, sizeof(temp)) == 0); + return temp; +} + +// Helper function to read the location from a device. + +CCS::LocType +Thermometer_impl:: +get_loc() +{ + char buf[32]; + assert(ICP_get(m_anum, "location", buf, sizeof(buf)) == 0); + return CORBA::string_dup(buf); +} + +// Helper function to set the location of a device. + +void +Thermometer_impl:: +set_loc(const char * loc) +{ + assert(ICP_set(m_anum, "location", loc) == 0); +} + +// Constructor. + +Thermometer_impl:: +Thermometer_impl(CCS::AssetType anum) : m_anum(anum) +{ + m_ctrl->add_impl(anum, this); // Add self to controller's set +} + +// Destructor. + +Thermometer_impl:: +~Thermometer_impl() +{ + if (m_ctrl->exists(m_anum)) + m_ctrl->add_impl(m_anum, 0); // Clear servant pointer +} + +// IDL model attribute. + +CCS::ModelType +Thermometer_impl:: +model() throw(CORBA::SystemException) +{ + return get_model(); +} + +// IDL asset_num attribute. + +CCS::AssetType +Thermometer_impl:: +asset_num() throw(CORBA::SystemException) +{ + return m_anum; +} + +// IDL temperature attribute. + +CCS::TempType +Thermometer_impl:: +temperature() throw(CORBA::SystemException) +{ + return get_temp(); +} + +// IDL location attribute accessor. + +CCS::LocType +Thermometer_impl:: +location() throw(CORBA::SystemException) +{ + return get_loc(); +} + +// IDL remove operation. + +void +Thermometer_impl:: +remove() throw(CORBA::SystemException) +{ + m_ctrl->remove_impl(m_anum); + assert(ICP_offline(m_anum) == 0); + // delete this; +} + +// IDL location attribute modifier. + +void +Thermometer_impl:: +location(const char *loc) throw(CORBA::SystemException) +{ + set_loc(loc); +} + +//---------------------------------------------------------------- + +// Helper function to get a thermostat's nominal temperature. + +CCS::TempType +Thermostat_impl:: +get_nominal_temp() +{ + short temp; + assert(ICP_get(m_anum, "nominal_temp", &temp, sizeof(temp)) == 0); + return temp; +} + +// Helper function to set a thermostat's nominal temperature. + +CCS::TempType +Thermostat_impl:: +set_nominal_temp(CCS::TempType new_temp) +throw(CCS::Thermostat::BadTemp) +{ + short old_temp; + + // We need to return the previous nominal temperature, + // so we first read the current nominal temperature before + // changing it. + assert( + ICP_get( + m_anum, "nominal_temp", &old_temp, sizeof(old_temp) + ) == 0 + ); + + // Now set the nominal temperature to the new value. + if (ICP_set(m_anum, "nominal_temp", &new_temp) != 0) { + + // If ICP_set() failed, read this thermostat's minimum + // and maximum so we can initialize the BadTemp exception. + CCS::Thermostat::BtData btd; + ICP_get( + m_anum, "MIN_TEMP", + &btd.min_permitted, sizeof(btd.min_permitted) + ); + ICP_get( + m_anum, "MAX_TEMP", + &btd.max_permitted, sizeof(btd.max_permitted) + ); + btd.requested = new_temp; + btd.error_msg = CORBA::string_dup( + new_temp > btd.max_permitted ? "Too hot" : "Too cold" + ); + throw CCS::Thermostat::BadTemp(btd); + } + return old_temp; +} + +// Constructor. + +Thermostat_impl:: +Thermostat_impl(CCS::AssetType anum) : Thermometer_impl(anum) +{ + // Intentionally empty. +} + +// Destructor. + +Thermostat_impl:: +~Thermostat_impl() +{ + // Intentionally empty. +} + +// IDL get_nominal operation. + +CCS::TempType +Thermostat_impl:: +get_nominal() throw(CORBA::SystemException) +{ + return get_nominal_temp(); +} + +// IDL set_nominal operation. + +CCS::TempType +Thermostat_impl:: +set_nominal(CCS::TempType new_temp) +throw(CORBA::SystemException, CCS::Thermostat::BadTemp) +{ + return set_nominal_temp(new_temp); +} + +//---------------------------------------------------------------- + +// Helper function to add an entry to the asset map. + +void +Controller_impl:: +add_impl(CCS::AssetType anum, Thermometer_impl * tip) +{ + m_assets[anum] = tip; +} + +// Helper function to remove an entry from the asset map. + +void +Controller_impl:: +remove_impl(CCS::AssetType anum) +{ + m_assets.erase(anum); +} + +// Helper function to locate a servant in the asset map. + +bool +Controller_impl:: +exists(CCS::AssetType anum) +{ + return m_assets.find(anum) != m_assets.end(); +} + +// Constructor + +Controller_impl:: +Controller_impl( + PortableServer::POA_ptr poa, + const char * asset_file +) throw(int) : m_poa(PortableServer::POA::_duplicate(poa)), + m_asset_file(asset_file) +{ + fstream afile(m_asset_file.in(), ios::in|ios::out, 0666); + if (!afile) { + cerr << "Cannot open " << m_asset_file.in() << endl; + throw 0; + } + CCS::AssetType anum; + while (afile >> anum) + m_assets[anum] = 0; + //afile.close(); + //if (!afile) { + // cerr << "Cannot close " << m_asset_file << endl; + // throw 0; + //} +} + +// Destructor + +Controller_impl:: +~Controller_impl() +{ + // Write out the current set of asset numbers + // and clean up all servant instances. + ofstream afile(m_asset_file.in()); + if (!afile) { + cerr << "Cannot open " << m_asset_file.in() << endl; + assert(0); + } + AssetMap::iterator i; + for (i = m_assets.begin(); i != m_assets.end(); i++) { + afile << i->first << endl; + if (!afile) { + cerr << "Cannot update " << m_asset_file.in() << endl; + assert(0); + } + delete i->second; + } + afile.close(); + if (!afile) { + cerr << "Cannot close " << m_asset_file.in() << endl; + assert(0); + } +} + +CCS::Thermometer_ptr +Controller_impl:: +create_thermometer(CCS::AssetType anum, const char * loc) +throw(CORBA::SystemException, CCS::Controller::DuplicateAsset) +{ + if (anum % 2 == 0) + throw CORBA::BAD_PARAM(); // Thermometers have odd numbers + if (exists(anum)) + throw CCS::Controller::DuplicateAsset(); + + assert(ICP_online(anum) == 0); + assert(ICP_set(anum, "location", loc) == 0); + add_impl(anum, 0); + return make_dref(m_poa.in(), anum); +} + +CCS::Thermostat_ptr +Controller_impl:: +create_thermostat( + CCS::AssetType anum, + const char* loc, + CCS::TempType temp) +throw( + CORBA::SystemException, + CCS::Controller::DuplicateAsset, + CCS::Thermostat::BadTemp) +{ + if (anum % 2 != 0) + throw CORBA::BAD_PARAM(); // Thermostats have even numbers + if (exists(anum)) + throw CCS::Controller::DuplicateAsset(); + + assert(ICP_online(anum) == 0); + assert(ICP_set(anum, "location", loc) == 0); + // Set the nominal temperature. + if (ICP_set(anum, "nominal_temp", &temp) != 0) { + + // If ICP_set() failed, read this thermostat's minimum + // and maximum so we can initialize the BadTemp exception. + CCS::Thermostat::BtData btd; + ICP_get( + anum, "MIN_TEMP", + &btd.min_permitted, sizeof(btd.min_permitted) + ); + ICP_get( + anum, "MAX_TEMP", + &btd.max_permitted, sizeof(btd.max_permitted) + ); + btd.requested = temp; + btd.error_msg = CORBA::string_dup( + temp > btd.max_permitted ? "Too hot" : "Too cold" + ); + ICP_offline(anum); + throw CCS::Thermostat::BadTemp(btd); + } + + add_impl(anum, 0); + CORBA::Object_var obj = make_dref(m_poa.in(), anum); + return CCS::Thermostat::_narrow(obj.in()); +} + +// IDL list operation. + +CCS::Controller::ThermometerSeq * +Controller_impl:: +list() throw(CORBA::SystemException) +{ + // Create a new thermometer sequence. Because we know + // the number of elements we will put onto the sequence, + // we use the maximum constructor. + CCS::Controller::ThermometerSeq_var listv + = new CCS::Controller::ThermometerSeq(m_assets.size()); + listv->length(m_assets.size()); + + // Loop over the m_assets set and create a + // reference for each device. + CORBA::ULong count = 0; + AssetMap::iterator i; + for (i = m_assets.begin(); i != m_assets.end(); i++) + listv[count++] = make_dref(m_poa.in(), i->first); + return listv._retn(); +} + +// IDL change operation. + +void +Controller_impl:: +change( + const CCS::Controller::ThermostatSeq & tlist, + CORBA::Short delta +) throw(CORBA::SystemException, CCS::Controller::EChange) +{ + CCS::Controller::EChange ec; // Just in case we need it + + // We cannot add a delta value to a thermostat's temperature + // directly, so for each thermostat, we read the nominal + // temperature, add the delta value to it, and write + // it back again. + for (CORBA::ULong i = 0; i < tlist.length(); i++) { + if (CORBA::is_nil(tlist[i])) + continue; // Skip nil references + + // Read nominal temp and update it. + CCS::TempType tnom = tlist[i]->get_nominal(); + tnom += delta; + try { + tlist[i]->set_nominal(tnom); + } + catch (const CCS::Thermostat::BadTemp &bt) { + // If the update failed because the temperature + // is out of range, we add the thermostat's info + // to the errors sequence. + CORBA::ULong len = ec.errors.length(); + ec.errors.length(len + 1); + ec.errors[len].tmstat_ref = tlist[i]; + ec.errors[len].info = bt.details; + } + } + + // If we encountered errors in the above loop, + // we will have added elements to the errors sequence. + if (ec.errors.length() != 0) + throw ec; +} + +// IDL find operation + +void +Controller_impl:: +find(CCS::Controller::SearchSeq & slist) +throw(CORBA::SystemException) +{ + // Loop over input list and lookup each device. + CORBA::ULong listlen = slist.length(); + for (CORBA::ULong i = 0; i < listlen; i++) { + + AssetMap::iterator where; // Iterator for asset set + int num_found = 0; // Num matched per iteration + + // Assume we will not find a matching device. + slist[i].device = CCS::Thermometer::_nil(); + + // Work out whether we are searching by asset, + // model, or location. + CCS::Controller::SearchCriterion sc = slist[i].key._d(); + if (sc == CCS::Controller::ASSET) { + // Search for matching asset number. + where = m_assets.find(slist[i].key.asset_num()); + if (where != m_assets.end()) + slist[i].device = make_dref(m_poa.in(), where->first); + } else { + // Search for model or location string. + const char *search_str; + if (sc == CCS::Controller::LOCATION) + search_str = slist[i].key.loc(); + else + search_str = slist[i].key.model_desc(); + + // Find first matching device (if any). + where = find_if( + m_assets.begin(), m_assets.end(), + StrFinder(sc, search_str) + ); + + // While there are matches... + while (where != m_assets.end()) { + if (num_found == 0) { + // First match overwrites reference + // in search record. + slist[i].device = make_dref(m_poa.in(), where->first); + } else { + // Further matches each append a new + // element to the search sequence. + CORBA::ULong len = slist.length(); + slist.length(len + 1); + slist[len].key = slist[i].key; + slist[len].device = make_dref(m_poa.in(), where->first); + } + num_found++; + + // Find next matching device with this key. + where = find_if( + ++where, m_assets.end(), + StrFinder(sc, search_str) + ); + } + } + } +} + +//---------------------------------------------------------------- + +DeviceLocator_impl:: +DeviceLocator_impl(Controller_impl * ctrl) : m_ctrl(ctrl) +{ + // Intentionally empty +} + +PortableServer::Servant +DeviceLocator_impl:: +preinvoke( + const PortableServer::ObjectId & oid, + PortableServer::POA_ptr /*poa*/, + const char * operation, + void * & /*cookie*/, + CORBA_Environment & +) throw(CORBA::SystemException, PortableServer::ForwardRequest) +{ + // Convert object id into asset number. + CORBA::String_var oid_string; + try { + oid_string = PortableServer::ObjectId_to_string(oid); + } catch (const CORBA::BAD_PARAM &) { + throw CORBA::OBJECT_NOT_EXIST(); + } + + if (strcmp(oid_string.in(), Controller_oid) == 0) + return m_ctrl; + + istrstream istr(oid_string.in()); + CCS::AssetType anum; + istr >> anum; + if (istr.fail()) + throw CORBA::OBJECT_NOT_EXIST(); + + // Check whether the device is known. + if (!m_ctrl->exists(anum)) + throw CORBA::OBJECT_NOT_EXIST(); + + // Look at the object map to find out whether + // we have a servant in memory. + Thermometer_impl * servant; + ActiveObjectMap::iterator servant_pos = m_aom.find(anum); + if (servant_pos == m_aom.end()) { + // No servant in memory. If evictor queue is full, + // evict servant at head of queue. + if (m_eq.size() == MAX_EQ_SIZE) { + servant = m_eq.back(); + m_aom.erase(servant->m_anum); + m_eq.pop_back(); + delete servant; + } + // Instantiate correct type of servant. + char buf[32]; + assert(ICP_get(anum, "model", buf, sizeof(buf)) == 0); + if (strcmp(buf, "Sens-A-Temp") == 0) + servant = new Thermometer_impl(anum); + else + servant = new Thermostat_impl(anum); + } else { + // Servant already in memory. + servant = *(servant_pos->second); // Remember servant + m_eq.erase(servant_pos->second); // Remove from queue + + // If operation is "remove", also remove entry from + // active object map -- the object is about to be deleted. + if (strcmp(operation, "remove") == 0) + m_aom.erase(servant_pos); + } + + // We found a servant, or just instantiated it. + // If the operation is not a remove, move + // the servant to the tail of the evictor queue + // and update its queue position in the map. + if (strcmp(operation, "remove") != 0) { + m_eq.push_front(servant); + m_aom[anum] = m_eq.begin(); + } + + return servant; +} + +//---------------------------------------------------------------- + +int +main(int argc, char * argv[]) +{ + CORBA::ORB_var orb; + + try { + // Initialize orb + orb = CORBA::ORB_init(argc, argv); + + // Get reference to Root POA. + CORBA::Object_var obj + = orb->resolve_initial_references("RootPOA"); + PortableServer::POA_var poa + = PortableServer::POA::_narrow(obj.in()); + + // Get POA manager + PortableServer::POAManager_var poa_mgr = poa->the_POAManager(); + + // Create a policy list. We use persistent objects with + // user-assigned IDs, and explicit activation. + CORBA::PolicyList policy_list; + policy_list.length(6); + policy_list[0] = poa->create_lifespan_policy( + PortableServer::TRANSIENT // REVISIT + ); + policy_list[1] = poa->create_id_assignment_policy( + PortableServer::USER_ID + ); + policy_list[2] = poa->create_implicit_activation_policy( + PortableServer::NO_IMPLICIT_ACTIVATION + ); + policy_list[3] = poa->create_request_processing_policy( + PortableServer::USE_SERVANT_MANAGER + ); + policy_list[4] = poa->create_servant_retention_policy( + PortableServer::NON_RETAIN + ); + policy_list[5] = poa->create_thread_policy( + PortableServer::SINGLE_THREAD_MODEL + ); + + // Create a POA for all CCS elements. + PortableServer::POA_var ccs_poa + = poa->create_POA("CCS_POA", poa_mgr.in(), policy_list); + + // Create a controller and set static m_ctrl member + // for thermostats and thermometers. + Controller_impl ctrl_servant(ccs_poa.in(), "/tmp/CCS_assets"); + Thermometer_impl::m_ctrl = &ctrl_servant; + + // Create a reference for the controller and + // create the corresponding CORBA object. + PortableServer::ObjectId_var oid + = PortableServer::string_to_ObjectId(Controller_oid); + obj = ccs_poa->create_reference_with_id( + oid.in(), "IDL:acme.com/CCS/Controller:1.0" + ); + + // Write a reference for the controller to stdout. + CORBA::String_var str = orb->object_to_string(obj.in()); + cout << str.in() << endl << endl; + + // Instantiate the servant locator for devices. + DeviceLocator_impl my_locator(&ctrl_servant); + PortableServer::ServantManager_var locator + = my_locator._this(); + + // Set servant locator. + ccs_poa->set_servant_manager(locator.in()); + + // Activate the POA manager. + poa_mgr->activate(); + + // Accept requests + orb->run(); + } + catch (const CORBA::Exception & e) { + cerr << "Uncaught CORBA exception: " << e << endl; + return 1; + } + catch (...) { + assert(0); // Uncaught exception, dump core + } + return 0; +} diff --git a/TAO/examples/Advanced/ch_12/server.h b/TAO/examples/Advanced/ch_12/server.h new file mode 100644 index 00000000000..6ee21ee87c9 --- /dev/null +++ b/TAO/examples/Advanced/ch_12/server.h @@ -0,0 +1,237 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_12 +// +// = FILENAME +// server.h +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#ifndef server_HH_ +#define server_HH_ + +#include "CCSS.h" +#include "icp.h" // mine +#include +#include +//#include +//#include + + +class Controller_impl; + +class Thermometer_impl : public virtual POA_CCS::Thermometer { +public: + // CORBA attributes + virtual CCS::ModelType model() + throw(CORBA::SystemException); + virtual CCS::AssetType asset_num() + throw(CORBA::SystemException); + virtual CCS::TempType temperature() + throw(CORBA::SystemException); + virtual CCS::LocType location() + throw(CORBA::SystemException); + virtual void location(const char *loc) + throw(CORBA::SystemException); + virtual void remove() + throw(CORBA::SystemException); + + // Constructor & destructor + Thermometer_impl(CCS::AssetType anum); + virtual ~Thermometer_impl(); + + static Controller_impl * m_ctrl; // My controller + const CCS::AssetType m_anum; // My asset number + +private: + // Helper functions + CCS::ModelType get_model(); + CCS::TempType get_temp(); + CCS::LocType get_loc(); + void set_loc(const char * new_loc); + + // Copy and assignment not supported + Thermometer_impl(const Thermometer_impl &); + void operator=(const Thermometer_impl &); +}; + +class Thermostat_impl : + public virtual POA_CCS::Thermostat, + public virtual Thermometer_impl { +public: + // CORBA operations + virtual CCS::TempType get_nominal() + throw(CORBA::SystemException); + virtual CCS::TempType set_nominal( + CCS::TempType new_temp + ) throw( + CORBA::SystemException, + CCS::Thermostat::BadTemp + ); + + // Constructor and destructor + Thermostat_impl(CCS::AssetType anum); + virtual ~Thermostat_impl(); + +private: + // Helper functions + CCS::TempType get_nominal_temp(); + CCS::TempType set_nominal_temp(CCS::TempType new_temp) + throw(CCS::Thermostat::BadTemp); + + // Copy and assignment not supported + Thermostat_impl(const Thermostat_impl &); + void operator=(const Thermostat_impl &); +}; + +class Controller_impl : public virtual POA_CCS::Controller { +public: + // CORBA operations + virtual CCS::Controller::ThermometerSeq * + list() throw(CORBA::SystemException); + virtual void + find(CCS::Controller::SearchSeq & slist) + throw(CORBA::SystemException); + virtual void + change( + const CCS::Controller::ThermostatSeq & tlist, + CORBA::Short delta + ) throw( + CORBA::SystemException, + CCS::Controller::EChange + ); + virtual CCS::Thermometer_ptr + create_thermometer( + CCS::AssetType anum, + const char* loc + ) throw( + CORBA::SystemException, + CCS::Controller::DuplicateAsset + ); + virtual CCS::Thermostat_ptr + create_thermostat( + CCS::AssetType anum, + const char* loc, + CCS::TempType temp + ) throw( + CORBA::SystemException, + CCS::Controller::DuplicateAsset, + CCS::Thermostat::BadTemp + ); + + // Constructor and destructor + Controller_impl( + PortableServer::POA_ptr poa, + const char * asset_file + ) throw(int); + virtual ~Controller_impl(); + + // Helper functions to allow access to the object map + void add_impl( + CCS::AssetType anum, + Thermometer_impl * tip + ); + void remove_impl(CCS::AssetType anum); + bool exists(CCS::AssetType anum); + +private: + // Map of existing assets. The servant pointer is null + // the corresponding servant is not in memory. + typedef map AssetMap; + AssetMap m_assets; + + // POA for thermometers and thermostats + PortableServer::POA_var m_poa; + + // Name of asset number file + CORBA::String_var m_asset_file; + + // Copy and assignment not supported + Controller_impl(const Controller_impl &); + void operator=(const Controller_impl &); + + // Function object for the find_if algorithm to search for + // devices by location and model string. + class StrFinder { + public: + StrFinder( + CCS::Controller::SearchCriterion sc, + const char * str + ) : m_sc(sc), m_str(str) {} + bool operator()( + pair & p + ) const + { + char buf[32]; + switch (m_sc) { + case CCS::Controller::LOCATION: + ICP_get(p.first, "location", buf, sizeof(buf)); + break; + case CCS::Controller::MODEL: + ICP_get(p.first, "model", buf, sizeof(buf)); + break; + default: + assert(0); // Precondition violation + } + return strcmp(buf, m_str) == 0; + } + private: + CCS::Controller::SearchCriterion m_sc; + const char * m_str; + }; +}; + +class DeviceLocator_impl : + public virtual POA_PortableServer::ServantLocator { +public: + DeviceLocator_impl(Controller_impl * ctrl); + + virtual PortableServer::Servant + preinvoke( + const PortableServer::ObjectId & oid, + PortableServer::POA_ptr poa, + const char * operation, + void * & cookie, + CORBA_Environment & + ) throw( + CORBA::SystemException, + PortableServer::ForwardRequest); + virtual void + postinvoke( + const PortableServer::ObjectId & /*oid*/, + PortableServer::POA_ptr /*poa*/, + const char * /*operation*/, + void * /*cookie*/, + PortableServer::Servant /*servant*/, + CORBA_Environment & + ) throw(CORBA::SystemException) {} +private: + Controller_impl * m_ctrl; + + typedef list EvictorQueue; + typedef map + ActiveObjectMap; + + static const unsigned int MAX_EQ_SIZE = 100; + EvictorQueue m_eq; + ActiveObjectMap m_aom; + + // Copy and assignment not supported + DeviceLocator_impl(const DeviceLocator_impl &); + void operator=(const DeviceLocator_impl &); +}; + +#endif diff --git a/TAO/examples/Advanced/ch_18/CCS.idl b/TAO/examples/Advanced/ch_18/CCS.idl new file mode 100644 index 00000000000..c0daa0f995f --- /dev/null +++ b/TAO/examples/Advanced/ch_18/CCS.idl @@ -0,0 +1,103 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_18 +// +// = FILENAME +// CCS.idl +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + +#pragma prefix "acme.com" + +module CCS { + typedef unsigned long AssetType; + typedef string ModelType; + typedef short TempType; + typedef string LocType; + + interface Thermometer { + readonly attribute ModelType model; + readonly attribute AssetType asset_num; + readonly attribute TempType temperature; + attribute LocType location; + + void remove(); + }; + + interface Thermostat : Thermometer { + struct BtData { + TempType requested; + TempType min_permitted; + TempType max_permitted; + string error_msg; + }; + exception BadTemp { BtData details; }; + + TempType get_nominal(); + TempType set_nominal(in TempType new_temp) + raises(BadTemp); + }; + + interface Controller { + exception DuplicateAsset {}; + + Thermometer create_thermometer( + in AssetType anum, + in LocType loc + ) raises(DuplicateAsset); + Thermostat create_thermostat( + in AssetType anum, + in LocType loc, + in TempType temp + ) raises(DuplicateAsset, Thermostat::BadTemp); + + typedef sequence ThermometerSeq; + typedef sequence ThermostatSeq; + + enum SearchCriterion { ASSET, LOCATION, MODEL }; + + union KeyType switch(SearchCriterion) { + case ASSET: + AssetType asset_num; + case LOCATION: + LocType loc; + case MODEL: + ModelType model_desc; + }; + + struct SearchType { + KeyType key; + Thermometer device; + }; + typedef sequence SearchSeq; + + struct ErrorDetails { + Thermostat tmstat_ref; + Thermostat::BtData info; + }; + typedef sequence ErrSeq; + + exception EChange { + ErrSeq errors; + }; + + ThermometerSeq list(); + void find(inout SearchSeq slist); + void change( + in ThermostatSeq tlist, in short delta + ) raises(EChange); + + }; +}; diff --git a/TAO/examples/Advanced/ch_18/CHANGES b/TAO/examples/Advanced/ch_18/CHANGES new file mode 100644 index 00000000000..404883d09de --- /dev/null +++ b/TAO/examples/Advanced/ch_18/CHANGES @@ -0,0 +1,98 @@ +$Id$ + +Changelog for chapter 8 and 10 example in "Advanced CORBA +Programming with C++" by Michi Henning and Steve Vinoski, +Copyright 1999, Addison-Wesley, Reading, MA. The following +changes have been made to the book's source code to make the +example work with TAO and with various platforms and compilers. + +_______________________________________________________________________________ +ESSENTIAL CHANGES: + 1. Changed filename extensions from .hh and .cc to .h + and .cpp, and made all necessary changes in file content. + + 2. a) Commented-out "#include " in server.h + + b) Added #include "icp.h" to server.h. + + c) changed #include to + in server.cpp and client.cpp + + d) Unnecessary standard includes of , , + and must be removed or moved to follow the + local includes in server.h, server.cpp, client.cpp, and icp.cpp. + + e) The following files may need their includes further rearranged + to avoid warnings and errors (g++). The following orderings + seem to work fine: + - server.cpp: "server.h", , "icp.h", + , + - server.h: "CCSS.h", "icp.h", , + + 3. Added CORBA_Environment variable to + DeviceLocator::preinvoke() and ::postinvoke() + in server.h and server.cpp to match the signatures of parent + methods in TAO's ServanLocator class. + + 4. removed if 0 code surrounding + operator<<(ostream & os, const CCS::Controller::EChange & ec) + definition in server.cpp and client.cpp. + + 5. commented-out "delete this;" from method + Thermometer_impl::remove() in server.cpp. + (Change should soon be reflected in authors' code) + +_______________________________________________________________________________ +ADDITIONAL CHANGES: + 6. Added .in() to _var parameters wherever needed: + -client.cpp: + 4 times in operator<<(ostream, CCS::Thermometer_ptr) + 3 times in resolve_init() + 3 times in resolve_name() + 5 times in main() + Also added .inout() 2 times in main() for parameters to set_temp() + + -server.cpp: + 3 changes in resolve_init() + 2 changes in make_dref() + 2 changes in Controller_impl::Controller_impl() + 3 changes in Controller_impl::~Controller_impl() + 1 change in Controller_impl::create_thermometer() + 2 changes in Controller_impl::create_thermostat() + 1 change in Controller_impl::list() + 3 changes in Controller_impl::find() + 7 change in main() + + 7. created needed file at /tmp/CCS_DB. (location is hard-coded) + To run, move CCS_DB from this directory to /tmp on the + local machine. + + 8. fixed warnings by commented out unused parameters in + -DeviceLocator_impl::postinvoke(..) in server.h + -DeviceLocator_impl::preinvoke(..) in server.cpp + + 9. MAX_EQ_SIZE changed from int to unsigned int + in class DeviceLocator_impl in server.h. + + 10. added cast to unsigned long in ~ICP_Persist() in icp.cpp: + db << (unsigned long)(i->second.type) << endl; + +_______________________________________________________________________________ +To Do: + - fix error on 4 cases of fstream.close() + in server.cpp and icp.cpp, now commented-out + + + + + + + + + + + + + + + diff --git a/TAO/examples/Advanced/ch_18/Makefile b/TAO/examples/Advanced/ch_18/Makefile new file mode 100644 index 00000000000..5ebb8b39e2d --- /dev/null +++ b/TAO/examples/Advanced/ch_18/Makefile @@ -0,0 +1,99 @@ +#---------------------------------------------------------------------------- +# +# $Id$ +# +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +ifndef TAO_ROOT + TAO_ROOT = $(ACE_ROOT)/TAO +endif + +LDLIBS = -lorbsvcs -lTAO +IDL_SRC = CCSC.cpp CCSS.cpp +IDL_HDR = CCSC.h CCSS.h + +PROG_SRCS = \ + client.cpp \ + server.cpp \ + icp.cpp + +SRC = $(IDL_SRC) $(PROG_SRCS) + +SIMPLE_CLT_OBJS = \ + CCSC.o \ + CCSS.o \ + client.o + +SIMPLE_SVR_OBJS = \ + CCSC.o \ + CCSS.o \ + server.o \ + icp.o + + +BIN2 = server \ + client + +#### If the TAO orbsvcs library wasn't built with sufficient components, +#### don't try to build here. +TAO_ORBSVCS := $(shell sh $(ACE_ROOT)/bin/ace_components --orbsvcs) +ifeq (Naming,$(findstring Naming,$(TAO_ORBSVCS))) + BIN = $(BIN2) +endif # Naming + +BUILD = $(BIN) +VLDLIBS = $(LDLIBS:%=%$(VAR)) +VBIN = $(BIN:%=%$(VAR)) + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(ACE_ROOT)/include/makeinclude/macros.GNU +include $(TAO_ROOT)/rules.tao.GNU +include $(ACE_ROOT)/include/makeinclude/rules.common.GNU +include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU +include $(ACE_ROOT)/include/makeinclude/rules.local.GNU +include $(TAO_ROOT)/taoconfig.mk + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- +LDFLAGS += -L$(TAO_ROOT)/orbsvcs/orbsvcs -L$(TAO_ROOT)/tao -L$(ACE_ROOT)/ace +CPPFLAGS += -I$(TAO_ROOT)/orbsvcs + +.PRECIOUS: CCSC.cpp CCSC.i CCSC.h +.PRECIOUS: CCSS.cpp CCSS.i CCSS.h +.PRECIOUS: CCSS_T.cpp CCSS_T.i CCSS_T.h + +override TAO_IDLFLAGS += -hc .hh -hs S.hh -hT S_T.hh \ + -cs C.cc -ci C.i \ + -ss S.cc -sT S_T.cc +CCFLAGS += -fimplicit-templates -frtti -O0 + +$(IDL_SRC): CCS.idl + $(TAO_ROOT)/TAO_IDL/tao_idl CCS.idl -hc .h -hs S.h -hT S_T.h \ + -cs C.cpp \ + -ss S.cpp -sT S_T.cpp +server: $(addprefix $(VDIR),$(SIMPLE_SVR_OBJS)) + $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS) $(POSTLINK) + +client: $(addprefix $(VDIR),$(SIMPLE_CLT_OBJS)) + $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS) $(POSTLINK) + +realclean: clean + -/bin/$(RM) -rf CCSC.* CCSS.* CCSS_T.* CCS.h + +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + + + + + + diff --git a/TAO/examples/Advanced/ch_18/README b/TAO/examples/Advanced/ch_18/README new file mode 100644 index 00000000000..5e0856df7d7 --- /dev/null +++ b/TAO/examples/Advanced/ch_18/README @@ -0,0 +1,45 @@ +$Id$ + +Chapter 18 example +______________________________________________________________________________ +This example been taken from the book "Advanced CORBA Programming with C++" +by Michi Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +MA. To make the examples work with TAO, some minor modifications to the +source code have been made, with permission, by Mike Moran . +All of these changes are documented in the file CHANGES, in this directory. +______________________________________________________________________________ + + +Summary: + This example adds the use of the Naming Service to the climate control + system of chapter 12. + +Building: + This example must be built with native C++ exceptions, and with an ACE/TAO + build with exceptions. Make sure to use TAO_FLAG Ge=0 to ensure that the + IDL generated code uses c++ exceptions rather than creating + CORBA_Environment variables. + + With GNU make, simply type + % make exceptions=1 + to create the executable server and client. + + Also, make sure that the Naming Service executable has been built at + $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service. + +server: + The server takes no parameters nor command line options and registers the + controller object with the naming service. The server then waits + infinitely for clients requests. + +client: + The client gets reference to the controller through the naming service, + makes several remote calls on this controller, and terminates. + +run_test.pl: + The script starts up a new Naming Service, starts thc server and client, + and when the client has completed terminates the server and NamingService. + + + + diff --git a/TAO/examples/Advanced/ch_18/client.cpp b/TAO/examples/Advanced/ch_18/client.cpp new file mode 100644 index 00000000000..bdf1db1f6b6 --- /dev/null +++ b/TAO/examples/Advanced/ch_18/client.cpp @@ -0,0 +1,349 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_18 +// +// = FILENAME +// client.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + +#include "CCS.h" // ORB-specific +#include +// #include +// #include +// ---------------------------------------------------------------- + +template +typename T::_ptr_type +resolve_init(CORBA::ORB_ptr orb, const char * id) +{ + CORBA::Object_var obj; + try { + obj = orb->resolve_initial_references(id); + } + catch (const CORBA::ORB::InvalidName & e) { + throw; + } + catch (const CORBA::Exception & e) { + cerr << "Cannot get initial reference for " + << id << ": " << e << endl; + throw 0; + } + assert(!CORBA::is_nil(obj.in())); + + typename T::_var_type ref; + try { + ref = T::_narrow(obj.in()); + } + catch (const CORBA::Exception & e) { + cerr << "Cannot narrow reference for " + << id << ": " << e << endl; + throw 0; + } + if (CORBA::is_nil(ref.in())) { + cerr << "Incorrect type of reference for " + << id << endl; + throw 0; + } + return ref._retn(); +} + +//---------------------------------------------------------------- + +template +typename T::_ptr_type +resolve_name( + CosNaming::NamingContext_ptr nc, + const CosNaming::Name & name) +{ + CORBA::Object_var obj; + try { + obj = nc->resolve(name); + } + catch (const CosNaming::NamingContext::NotFound & e) { + throw; + } + catch (const CORBA::Exception & e) { + cerr << "Cannot resolve binding: " << e << endl; + throw 0; + } + if (CORBA::is_nil(obj.in())) { + cerr << "Nil binding in Naming Service" << endl; + throw 0; + } + + typename T::_var_type ref; + try { + ref = T::_narrow(obj.in()); + } + catch (const CORBA::Exception & e) { + cerr << "Cannot narrow reference: " << e << endl; + throw 0; + } + if (CORBA::is_nil(ref.in())) { + cerr << "Reference has incorrect type" << endl; + throw 0; + } + return ref._retn(); +} + +//---------------------------------------------------------------- + +// Generic ostream inserter for exceptions. Inserts the exception +// name, if available, and the repository ID otherwise. + +//#if 0 // This inserter may or may not be needed for your ORB. + +static ostream & +operator<<(ostream & os, const CORBA::Exception & e) +{ + CORBA::Any tmp; + tmp <<= e; + + CORBA::TypeCode_var tc = tmp.type(); + const char * p = tc->name(); + if (*p != '\0') + os << p; + else + os << tc->id(); + return os; +} + +//#endif + +//---------------------------------------------------------------- + +// Show the details for a thermometer or thermostat. + +static ostream & +operator<<(ostream &os, CCS::Thermometer_ptr t) +{ + // Check for nil. + if (CORBA::is_nil(t)) { + os << "Cannot show state for nil reference." << endl; + return os; + } + + // Try to narrow and print what kind of device it is. + CCS::Thermostat_var tmstat = CCS::Thermostat::_narrow(t); + os << (CORBA::is_nil(tmstat.in()) ? "Thermometer:" : "Thermostat:") + << endl; + + // Show attribute values. + CCS::ModelType_var model = t->model(); + CCS::LocType_var location = t->location(); + os << "\tAsset number: " << t->asset_num() << endl; + os << "\tModel : " << model.in() << endl; + os << "\tLocation : " << location.in() << endl; + os << "\tTemperature : " << t->temperature() << endl; + + // If device is a thermostat, show nominal temperature. + if (!CORBA::is_nil(tmstat.in())) + os << "\tNominal temp: " << tmstat->get_nominal() << endl; + return os; +} + +//---------------------------------------------------------------- + +// Show the information in a BtData struct. + +static ostream & +operator<<(ostream &os, const CCS::Thermostat::BtData &btd) +{ + os << "CCS::Thermostat::BtData details:" << endl; + os << "\trequested : " << btd.requested << endl; + os << "\tmin_permitted: " << btd.min_permitted << endl; + os << "\tmax_permitted: " << btd.max_permitted << endl; + os << "\terror_msg : " << btd.error_msg << endl; + return os; +} + +//---------------------------------------------------------------- + +// Loop over the sequence of records in an EChange exception and +// show the details of each record. + +static ostream & +operator<<(ostream &os, const CCS::Controller::EChange &ec) +{ + for (CORBA::ULong i = 0; i < ec.errors.length(); i++) { + os << "Change failed:" << endl; + os << ec.errors[i].tmstat_ref.in(); // Overloaded << + os << ec.errors[i].info << endl; // Overloaded << + } + return os; +} + +//---------------------------------------------------------------- + +// Change the temperature of a thermostat. + +static void +set_temp(CCS::Thermostat_ptr tmstat, CCS::TempType new_temp) +{ + if (CORBA::is_nil(tmstat)) // Don't call via nil reference + return; + + CCS::AssetType anum = tmstat->asset_num(); + try { + cout << "Setting thermostat " << anum + << " to " << new_temp << " degrees." << endl; + CCS::TempType old_nominal = tmstat->set_nominal(new_temp); + cout << "Old nominal temperature was: " + << old_nominal << endl; + cout << "New nominal temperature is: " + << tmstat->get_nominal() << endl; + } catch (const CCS::Thermostat::BadTemp &bt) { + cerr << "Setting of nominal temperature failed." << endl; + cerr << bt.details << endl; // Overloaded << + } +} + +//---------------------------------------------------------------- + +int +main(int argc, char * argv[]) +{ + try { + // Initialize the ORB + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + // Check arguments + if (argc != 1) { + cerr << "Usage: client" << endl; + throw 0; + } + + // Get reference to initial naming context. + CosNaming::NamingContext_var inc + = resolve_init( + orb.in(), "NameService" + ); + + // Look for controller in the Naming Service. + CosNaming::Name n; + n.length(2); + n[0].id = CORBA::string_dup("CCS"); + n[1].id = CORBA::string_dup("Controller"); + CCS::Controller_var ctrl; + try { + ctrl = resolve_name(inc.in(), n); + } catch (const CosNaming::NamingContext::NotFound &) { + cerr << "No controller in Naming Service" << endl; + throw(0); + } + + // Get list of devices + CCS::Controller::ThermometerSeq_var list = ctrl->list(); + + // Show number of devices. + CORBA::ULong len = list->length(); + cout << "Controller has " << len << " device"; + if (len != 1) + cout << "s"; + cout << "." << endl; + + CCS::Thermometer_var t = ctrl->create_thermometer(27, "Room 1"); + CCS::Thermostat_var ts = ctrl->create_thermostat(28, "Room 2", 48); + CCS::Thermostat_var ts2 = ctrl->create_thermostat(30, "Room 3", 48); + CCS::Thermostat_var ts3 = ctrl->create_thermostat(32, "Room 3", 68); + CCS::Thermostat_var ts4 = ctrl->create_thermostat(34, "Room 3", 68); + CCS::Thermostat_var ts5 = ctrl->create_thermostat(36, "Room 3", 48); + cout << t->location() << endl; + cout << ts->location() << endl; + cout << ts2->location() << endl; + t->remove(); + + list = ctrl->list(); + // Show details for each device. + for (CORBA::ULong i = 0; i < list->length(); i++) + cout << list[i]; + cout << endl; + + // Change the location of first device in the list + CCS::AssetType anum = list[0]->asset_num(); + cout << "Changing location of device " + << anum << "." << endl; + list[0]->location("Earth"); + // Check that the location was updated + cout << "New details for device " + << anum << " are:" << endl; + cout << list[0] << endl; + + // Find first thermostat in list. + CCS::Thermostat_var tmstat; + for ( CORBA::ULong i = 0; + i < list->length() && CORBA::is_nil(tmstat.in()); + i++) { + tmstat = CCS::Thermostat::_narrow(list[i]); + } + + // Check that we found a thermostat on the list. + if (CORBA::is_nil(tmstat.in())) { + cout << "No thermostat devices in list." << endl; + } else { + // Set temperature of thermostat to + // 50 degrees (should work). + set_temp(tmstat.inout(), 50); + cout << endl; + + // Set temperature of thermostat to + // -10 degrees (should fail). + set_temp(tmstat.inout(), -10); + } + + // Look for device in Rooms Earth and HAL. This must + // locate at least one device because we earlier changed + // the location of the first device to Room Earth. + cout << "Looking for devices in Earth and HAL." << endl; + CCS::Controller::SearchSeq ss; + ss.length(2); + ss[0].key.loc(CORBA::string_dup("Earth")); + ss[1].key.loc(CORBA::string_dup("HAL")); + ctrl->find(ss); + + // Show the devices found in that room. + for (CORBA::ULong i = 0; i < ss.length(); i++) + cout << ss[i].device.in(); // Overloaded << + cout << endl; + + // Increase the temperature of all thermostats + // by 40 degrees. First, make a new list (tss) + // containing only thermostats. + cout << "Increasing thermostats by 40 degrees." << endl; + CCS::Controller::ThermostatSeq tss; + for (CORBA::ULong i = 0; i < list->length(); i++) { + tmstat = CCS::Thermostat::_narrow(list[i]); + if (CORBA::is_nil(tmstat.in())) + continue; // Skip thermometers + len = tss.length(); + tss.length(len + 1); + tss[len] = tmstat; + } + + // Try to change all thermostats. + try { + ctrl->change(tss, 40); + } catch (const CCS::Controller::EChange &ec) { + cerr << ec; // Overloaded << + } + } catch (const CORBA::Exception & e) { + cerr << "Uncaught CORBA exception: " << e << endl; + return 1; + } catch (...) { + return 1; + } + return 0; +} diff --git a/TAO/examples/Advanced/ch_18/icp.cpp b/TAO/examples/Advanced/ch_18/icp.cpp new file mode 100644 index 00000000000..e8ba75d6ef7 --- /dev/null +++ b/TAO/examples/Advanced/ch_18/icp.cpp @@ -0,0 +1,386 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_18 +// +// = FILENAME +// icp.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#include +#include +#include +#include "icp.h" +// #include + +//---------------------------------------------------------------- + +enum DeviceType { thermometer, thermostat }; + +struct DeviceState { // State for a device + DeviceType type; + const char * model; + string location; + short nominal_temp; // For thermostats only +}; +typedef map StateMap; + +//---------------------------------------------------------------- + +const size_t MAXSTR = 32; // Max len of string including NUL + +const short MIN_TEMP = 40; // 40 F == 4.44 C +const short MAX_TEMP = 90; // 90 F == 32.22 C +const short DFLT_TEMP = 68; // 68 F == 20.00 C + +static StateMap dstate; // Map of known devices + +//---------------------------------------------------------------- + +// ICP_online() simulates adding a new device to the network by +// adding it to the dstate map. +// +// For this simple simulation, devices with odd asset numbers +// are thermometers and devices with even asset numbers +// are thermostats. +// +// Thermostats get an initial nominal temperature of DFLT_TEMP. +// The location string is intentionally left blank because it +// must be programmed by the controller after putting the device +// on-line (as should be the nominal temperature). +// +// If a device with the specified ID is already on-line, the +// return value is -1. A zero return value indicates success. + +extern "C" +int +ICP_online(unsigned long id) +{ + // Look for id in state map. + StateMap::iterator pos = dstate.find(id); + if (pos != dstate.end()) + return -1; // Already exists + + // Fill in state. + DeviceState ds; + ds.type = (id % 2) ? thermometer : thermostat; + ds.model = (ds.type == thermometer) + ? "Sens-A-Temp" : "Select-A-Temp"; + ds.nominal_temp = DFLT_TEMP; + + // Insert new device into map + dstate[id] = ds; + + return 0; +} + +//---------------------------------------------------------------- + +// ICP_offline() simulates removing a device from the network by +// removing it from the dstate map. If the device isn't known, the +// return value is -1. A zero return value indicates success. + +extern "C" +int +ICP_offline(unsigned long id) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + dstate.erase(id); + return 0; +} + +//---------------------------------------------------------------- + +// vary_temp() simulates the variation in actual temperature +// around a thermostat.The function randomly varies the +// temperature as a percentage of calls as follows: +// +// 3 degrees too cold: 5% +// 3 degrees too hot: 5% +// 2 degrees too cold: 10% +// 2 degrees too hot: 10% +// 1 degree too cold: 15% +// 1 degree too hot: 15% +// exact temperature: 40% + +static +short +vary_temp(short temp) +{ + long r = lrand48() % 50; + long delta; + if (r < 5) + delta = 3; + else if (r < 15) + delta = 2; + else if (r < 30) + delta = 1; + else + delta = 0; + if (lrand48() % 2) + delta = -delta; + return temp + delta; +} + +//---------------------------------------------------------------- + +// Function object. Locates a thermostat that is in the same room +// as the device at position pos. + +class ThermostatInSameRoom { +public: + ThermostatInSameRoom( + const StateMap::iterator & pos + ) : m_pos(pos) {} + bool operator()( + pair & p + ) const + { + return( + p.second.type == thermostat + && p.second.location + == m_pos->second.location + ); + } +private: + const StateMap::iterator & m_pos; +}; + +//---------------------------------------------------------------- + +// actual_temp() is a helper function to determine the actual +// temperature returned by a particular thermometer or thermostat. +// The pos argument indicates the device. +// +// The function locates all thermostats that are in the same room +// as the device denoted by pos and computes the average of all +// the thermostats' nominal temperatures. (If no thermostats are +// in the same room as the device, the function assumes that the +// average of the nominal temperatures is DFLT_TEMP.) +// +// The returned temperature varies from the average as +// determined by vary_temp(). + +static +short +actual_temp(const StateMap::iterator & pos) +{ + long sum = 0; + long count = 0; + StateMap::iterator where = find_if( + dstate.begin(), dstate.end(), + ThermostatInSameRoom(pos) + ); + while (where != dstate.end()) { + count++; + sum += where->second.nominal_temp; + where = find_if( + ++where, dstate.end(), + ThermostatInSameRoom(pos) + ); + } + return vary_temp(count == 0 ? DFLT_TEMP : sum / count); +} + +//---------------------------------------------------------------- + +// ICP_get() returns an attribute value of the device with the +// given id. The attribute is named by the attr parameter. The +// value is copied into the buffer pointed to by the value +// pointer. The len parameter is the size of the passed buffer, +// so ICP_get can avoid overrunning the buffer. +// +// By default, thermometers report a temperature that varies +// somewhat around DFLT_TEMP. However, if there is another +// thermostat in the same room as the the thermometer, the +// thermometer reports a temperature that varies around that +// thermostat's temperature. For several thermostats that are in +// the same room, the thermometer reports around the average +// nominal temperature of all the thermostats. +// +// Attempts to read from a non-existent device or to read a +// non-existent attribute return -1. A return value of zero +// indicates success. If the supplied buffer is too short to hold +// a value, ICP_get() silently truncates the value and +// returns success. + +extern "C" +int +ICP_get( + unsigned long id, + const char * attr, + void * value, + size_t len) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + + // Depending on the attribute, return the + // corresponding piece of state. + if (strcmp(attr, "model") == 0) { + strncpy((char *)value, pos->second.model, len); + } else if (strcmp(attr, "location") == 0) { + strncpy((char *)value, pos->second.location.c_str(), len); + } else if (strcmp(attr, "nominal_temp") == 0) { + if (pos->second.type != thermostat) + return -1; // Must be thermostat + memcpy( + value, &pos->second.nominal_temp, + min(len, sizeof(pos->second.nominal_temp)) + ); + } else if (strcmp(attr, "temperature") == 0) { + short temp = actual_temp(pos); + memcpy(value, &temp, min(len, sizeof(temp))); + } else if (strcmp(attr, "MIN_TEMP") == 0) { + memcpy(value, &MIN_TEMP, min(len, sizeof(MIN_TEMP))); + } else if (strcmp(attr, "MAX_TEMP") == 0) { + memcpy(value, &MAX_TEMP, min(len, sizeof(MAX_TEMP))); + } else { + return -1; // No such attribute + } + return 0; // OK +} + +//---------------------------------------------------------------- + +// ICP_set() sets the the attributed specified by attr to the +// value specified by value for the device with ID id. Attempts to +// write a string longer than MAXSTR bytes (including the +// terminating NUL) result in silent truncation of the string. +// Attempts to access a non-existent device or attribute +// return -1. Attempts to set a nominal temperature outside the +// legal range also return -1. A zero return value +// indicates success. + +extern "C" +int +ICP_set(unsigned long id, const char * attr, const void * value) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + + // Change either location or nominal temp, depending on attr. + if (strcmp(attr, "location") == 0) { + pos->second.location.assign( + (const char *)value, MAXSTR - 1 + ); + } else if (strcmp(attr, "nominal_temp") == 0) { + if (pos->second.type != thermostat) + return -1; // Must be thermostat + short temp; + memcpy(&temp, value, sizeof(temp)); + if (temp < MIN_TEMP || temp > MAX_TEMP) + return -1; + pos->second.nominal_temp = temp; + } else { + return -1; // No such attribute + } + return 0; // OK +} + +//---------------------------------------------------------------- + +#include + +class ICP_Persist { +public: + ICP_Persist(const char * file); + ~ICP_Persist(); +private: + string m_filename; +}; + +// Read device state from a file and initialize the dstate map. + +ICP_Persist:: +ICP_Persist(const char * file) : m_filename(file) +{ + // Open input file, creating it if necessary. + fstream db(m_filename.c_str(), ios::in|ios::out, 0666); + if (!db) { + cerr << "Error opening " << m_filename << endl; + exit(1); + } + + // Read device details, one attribute per line. + DeviceState ds; + unsigned long id; + while (db >> id) { + // Read device type and set model string accordingly. + int dtype; + db >> dtype; + ds.type = dtype == thermometer + ? thermometer : thermostat; + ds.model = dtype == thermometer + ? "Sens-A-Temp" : "Select-A-Temp"; + char loc[MAXSTR]; + db.get(loc[0]); // Skip newline + db.getline(loc, sizeof(loc)); // Read location + ds.location = loc; + if (ds.type == thermostat) + db >> ds.nominal_temp; // Read temperature + dstate[id] = ds; // Add entry to map + } + + //db.close(); + //if (!db) { + // cerr << "Error closing " << m_filename << endl; + // exit(1); + //} +} + +// Write device state to the file. + +ICP_Persist:: +~ICP_Persist() +{ + // Open input file, truncating it. + ofstream db(m_filename.c_str()); + if (!db) { + cerr << "Error opening " << m_filename << endl; + exit(1); + } + + // Write the state details for each device. + StateMap::iterator i; + for (i = dstate.begin(); i != dstate.end(); i++) { + db << i->first << endl; + db << (unsigned long)(i->second.type) << endl; + db << i->second.location << endl; + if (i->second.type == thermostat) + db << i->second.nominal_temp << endl; + } + if (!db) { + cerr << "Error writing " << m_filename << endl; + exit(1); + } + + db.close(); + if (!db) { + cerr << "Error closing " << m_filename << endl; + exit(1); + } +} + +// Instantiate a single global instance of the class. +static ICP_Persist mydb("/tmp/CCS_DB"); diff --git a/TAO/examples/Advanced/ch_18/icp.h b/TAO/examples/Advanced/ch_18/icp.h new file mode 100644 index 00000000000..68f6b120105 --- /dev/null +++ b/TAO/examples/Advanced/ch_18/icp.h @@ -0,0 +1,42 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_18 +// +// = FILENAME +// icp.h +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#ifndef _ICP_H +#define _ICP_H + +extern "C" { + int ICP_online(unsigned long id); // Add device + int ICP_offline(unsigned long id); // Remove device + int ICP_get( // Get attribute + unsigned long id, + const char * attr, + void * value, + size_t len + ); + int ICP_set( // Set attribute + unsigned long id, + const char * attr, + const void * value + ); +} + +#endif /* _ICP_H */ diff --git a/TAO/examples/Advanced/ch_18/run_test.pl b/TAO/examples/Advanced/ch_18/run_test.pl new file mode 100755 index 00000000000..b0da026b271 --- /dev/null +++ b/TAO/examples/Advanced/ch_18/run_test.pl @@ -0,0 +1,72 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "../../../../bin"; + +require ACEutils; +require Process; + +$status = 0; + +# amount of delay between starting servers and client +$sleeptime = 5; + + + +sub name_server +{ + my $prog = "..$DIR_SEPARATOR". + "..$DIR_SEPARATOR". + "..$DIR_SEPARATOR". + "orbsvcs$DIR_SEPARATOR". + "Naming_Service$DIR_SEPARATOR". + "Naming_Service$EXE_EXT"; + $NS = Process::Create ($prog,""); +} + + + +# create naming service, server, client +name_server (); +sleep $sleeptime; + +$server = Process::Create ($EXEPREFIX."server".$EXE_EXT, ""); +sleep $sleeptime; + +$client = Process::Create($EXEPREFIX."client".$EXE_EXT, ""); + + + +# wait for client to finish +if ($client->TimedWait (60) == -1) { + print STDERR "ERROR: client timedout\n"; + $status = 1; + $client->Kill (); $client->TimedWait (1); +} + + +# gracefully kill the server +$server->Terminate (); +if ($server->TimedWait (5) == -1) { + print STDERR "ERROR: cannot terminate the server\n"; + $server->Kill (); $server->TimedWait (1); + $status = 1; +} + +# gracefully kill the Naming Service +$NS->Terminate (); +if ($NS->TimedWait (5) == -1) { + print STDERR "ERROR: cannot terminate the server\n"; + $NS->Kill (); $server->TimedWait (1); + $status = 1; +} + +exit $status; + + + + diff --git a/TAO/examples/Advanced/ch_18/server.cpp b/TAO/examples/Advanced/ch_18/server.cpp new file mode 100644 index 00000000000..8cf4fac044a --- /dev/null +++ b/TAO/examples/Advanced/ch_18/server.cpp @@ -0,0 +1,791 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_18 +// +// = FILENAME +// server.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#include "server.h" +#include +#include "icp.h" +#include +#include + +// #include +// #include + +const char * Controller_oid = "Controller"; + +//---------------------------------------------------------------- + +template +typename T::_ptr_type +resolve_init(CORBA::ORB_ptr orb, const char * id) +{ + CORBA::Object_var obj; + try { + obj = orb->resolve_initial_references(id); + } + catch (const CORBA::ORB::InvalidName & e) { + throw; + } + catch (const CORBA::Exception & e) { + cerr << "Cannot get initial reference for " + << id << ": " << e << endl; + throw 0; + } + assert(!CORBA::is_nil(obj.in())); + + typename T::_var_type ref; + try { + ref = T::_narrow(obj.in()); + } + catch (const CORBA::Exception & e) { + cerr << "Cannot narrow reference for " + << id << ": " << e << endl; + throw 0; + } + if (CORBA::is_nil(ref.in())) { + cerr << "Incorrect type of reference for " + << id << endl; + throw 0; + } + return ref._retn(); +} + +//---------------------------------------------------------------- + +// Generic ostream inserter for exceptions. Inserts the exception +// name, if available, and the repository ID otherwise. + +//#if 0 // This inserter may or may not be needed for your ORB. + +static ostream & +operator<<(ostream & os, const CORBA::Exception & e) +{ + CORBA::Any tmp; + tmp <<= e; + + CORBA::TypeCode_var tc = tmp.type(); + const char * p = tc->name(); + if (*p != '\0') + os << p; + else + os << tc->id(); + return os; +} + +//#endif + +//---------------------------------------------------------------- + +// Helper function to create object references. + +static CCS::Thermometer_ptr +make_dref(PortableServer::POA_ptr poa, CCS::AssetType anum) +{ + // Convert asset number to OID. + ostrstream ostr; + ostr << anum << ends; + char * anum_str = ostr.str(); + PortableServer::ObjectId_var oid + = PortableServer::string_to_ObjectId(anum_str); + delete[] anum_str; + + // Look at the model via the network to determine + // the repository ID. + char buf[32]; + assert(ICP_get(anum, "model", buf, sizeof(buf)) == 0); + const char * rep_id = strcmp(buf, "Sens-A-Temp") == 0 + ? "IDL:acme.com/CCS/Thermometer:1.0" + : "IDL:acme.com/CCS/Thermostat:1.0"; + + // Make a new reference. + CORBA::Object_var obj + = poa->create_reference_with_id(oid.in(), rep_id); + return CCS::Thermometer::_narrow(obj.in()); +} + +//---------------------------------------------------------------- + +Controller_impl * Thermometer_impl::m_ctrl; // static member + +// Helper function to read the model string from a device. + +CCS::ModelType +Thermometer_impl:: +get_model() +{ + char buf[32]; + assert(ICP_get(m_anum, "model", buf, sizeof(buf)) == 0); + return CORBA::string_dup(buf); +} + +// Helper function to read the temperature from a device. + +CCS::TempType +Thermometer_impl:: +get_temp() +{ + short temp; + assert(ICP_get(m_anum, "temperature", &temp, sizeof(temp)) == 0); + return temp; +} + +// Helper function to read the location from a device. + +CCS::LocType +Thermometer_impl:: +get_loc() +{ + char buf[32]; + assert(ICP_get(m_anum, "location", buf, sizeof(buf)) == 0); + return CORBA::string_dup(buf); +} + +// Helper function to set the location of a device. + +void +Thermometer_impl:: +set_loc(const char * loc) +{ + assert(ICP_set(m_anum, "location", loc) == 0); +} + +// Constructor. + +Thermometer_impl:: +Thermometer_impl(CCS::AssetType anum) : m_anum(anum) +{ + m_ctrl->add_impl(anum, this); // Add self to controller's set +} + +// Destructor. + +Thermometer_impl:: +~Thermometer_impl() +{ + if (m_ctrl->exists(m_anum)) + m_ctrl->add_impl(m_anum, 0); // Clear servant pointer +} + +// IDL model attribute. + +CCS::ModelType +Thermometer_impl:: +model() throw(CORBA::SystemException) +{ + return get_model(); +} + +// IDL asset_num attribute. + +CCS::AssetType +Thermometer_impl:: +asset_num() throw(CORBA::SystemException) +{ + return m_anum; +} + +// IDL temperature attribute. + +CCS::TempType +Thermometer_impl:: +temperature() throw(CORBA::SystemException) +{ + return get_temp(); +} + +// IDL location attribute accessor. + +CCS::LocType +Thermometer_impl:: +location() throw(CORBA::SystemException) +{ + return get_loc(); +} + +// IDL remove operation. + +void +Thermometer_impl:: +remove() throw(CORBA::SystemException) +{ + m_ctrl->remove_impl(m_anum); + assert(ICP_offline(m_anum) == 0); + //delete this; +} + +// IDL location attribute modifier. + +void +Thermometer_impl:: +location(const char *loc) throw(CORBA::SystemException) +{ + set_loc(loc); +} + +//---------------------------------------------------------------- + +// Helper function to get a thermostat's nominal temperature. + +CCS::TempType +Thermostat_impl:: +get_nominal_temp() +{ + short temp; + assert(ICP_get(m_anum, "nominal_temp", &temp, sizeof(temp)) == 0); + return temp; +} + +// Helper function to set a thermostat's nominal temperature. + +CCS::TempType +Thermostat_impl:: +set_nominal_temp(CCS::TempType new_temp) +throw(CCS::Thermostat::BadTemp) +{ + short old_temp; + + // We need to return the previous nominal temperature, + // so we first read the current nominal temperature before + // changing it. + assert( + ICP_get( + m_anum, "nominal_temp", &old_temp, sizeof(old_temp) + ) == 0 + ); + + // Now set the nominal temperature to the new value. + if (ICP_set(m_anum, "nominal_temp", &new_temp) != 0) { + + // If ICP_set() failed, read this thermostat's minimum + // and maximum so we can initialize the BadTemp exception. + CCS::Thermostat::BtData btd; + ICP_get( + m_anum, "MIN_TEMP", + &btd.min_permitted, sizeof(btd.min_permitted) + ); + ICP_get( + m_anum, "MAX_TEMP", + &btd.max_permitted, sizeof(btd.max_permitted) + ); + btd.requested = new_temp; + btd.error_msg = CORBA::string_dup( + new_temp > btd.max_permitted ? "Too hot" : "Too cold" + ); + throw CCS::Thermostat::BadTemp(btd); + } + return old_temp; +} + +// Constructor. + +Thermostat_impl:: +Thermostat_impl(CCS::AssetType anum) : Thermometer_impl(anum) +{ + // Intentionally empty. +} + +// Destructor. + +Thermostat_impl:: +~Thermostat_impl() +{ + // Intentionally empty. +} + +// IDL get_nominal operation. + +CCS::TempType +Thermostat_impl:: +get_nominal() throw(CORBA::SystemException) +{ + return get_nominal_temp(); +} + +// IDL set_nominal operation. + +CCS::TempType +Thermostat_impl:: +set_nominal(CCS::TempType new_temp) +throw(CORBA::SystemException, CCS::Thermostat::BadTemp) +{ + return set_nominal_temp(new_temp); +} + +//---------------------------------------------------------------- + +// Helper function to add an entry to the asset map. + +void +Controller_impl:: +add_impl(CCS::AssetType anum, Thermometer_impl * tip) +{ + m_assets[anum] = tip; +} + +// Helper function to remove an entry from the asset map. + +void +Controller_impl:: +remove_impl(CCS::AssetType anum) +{ + m_assets.erase(anum); +} + +// Helper function to locate a servant in the asset map. + +bool +Controller_impl:: +exists(CCS::AssetType anum) +{ + return m_assets.find(anum) != m_assets.end(); +} + +// Constructor + +Controller_impl:: +Controller_impl( + PortableServer::POA_ptr poa, + const char * asset_file +) throw(int) : m_poa(PortableServer::POA::_duplicate(poa)), + m_asset_file(asset_file) +{ + fstream afile(m_asset_file.in(), ios::in|ios::out, 0666); + if (!afile) { + cerr << "Cannot open " << m_asset_file.in() << endl; + throw 0; + } + CCS::AssetType anum; + while (afile >> anum) + m_assets[anum] = 0; + //afile.close(); + //if (!afile) { + // cerr << "Cannot close " << m_asset_file << endl; + // throw 0; + //} +} + +// Destructor + +Controller_impl:: +~Controller_impl() +{ + // Write out the current set of asset numbers + // and clean up all servant instances. + ofstream afile(m_asset_file.in()); + if (!afile) { + cerr << "Cannot open " << m_asset_file.in() << endl; + assert(0); + } + AssetMap::iterator i; + for (i = m_assets.begin(); i != m_assets.end(); i++) { + afile << i->first << endl; + if (!afile) { + cerr << "Cannot update " << m_asset_file.in() << endl; + assert(0); + } + delete i->second; + } + //afile.close(); + //if (!afile) { + // cerr << "Cannot close " << m_asset_file << endl; + // assert(0); + //} +} + +CCS::Thermometer_ptr +Controller_impl:: +create_thermometer(CCS::AssetType anum, const char * loc) +throw(CORBA::SystemException, CCS::Controller::DuplicateAsset) +{ + if (anum % 2 == 0) + throw CORBA::BAD_PARAM(); // Thermometers have odd numbers + if (exists(anum)) + throw CCS::Controller::DuplicateAsset(); + + assert(ICP_online(anum) == 0); + assert(ICP_set(anum, "location", loc) == 0); + add_impl(anum, 0); + return make_dref(m_poa.in(), anum); +} + +CCS::Thermostat_ptr +Controller_impl:: +create_thermostat( + CCS::AssetType anum, + const char* loc, + CCS::TempType temp) +throw( + CORBA::SystemException, + CCS::Controller::DuplicateAsset, + CCS::Thermostat::BadTemp) +{ + if (anum % 2 != 0) + throw CORBA::BAD_PARAM(); // Thermostats have even numbers + if (exists(anum)) + throw CCS::Controller::DuplicateAsset(); + + assert(ICP_online(anum) == 0); + assert(ICP_set(anum, "location", loc) == 0); + // Set the nominal temperature. + if (ICP_set(anum, "nominal_temp", &temp) != 0) { + + // If ICP_set() failed, read this thermostat's minimum + // and maximum so we can initialize the BadTemp exception. + CCS::Thermostat::BtData btd; + ICP_get( + anum, "MIN_TEMP", + &btd.min_permitted, sizeof(btd.min_permitted) + ); + ICP_get( + anum, "MAX_TEMP", + &btd.max_permitted, sizeof(btd.max_permitted) + ); + btd.requested = temp; + btd.error_msg = CORBA::string_dup( + temp > btd.max_permitted ? "Too hot" : "Too cold" + ); + ICP_offline(anum); + throw CCS::Thermostat::BadTemp(btd); + } + + add_impl(anum, 0); + CORBA::Object_var obj = make_dref(m_poa.in(), anum); + return CCS::Thermostat::_narrow(obj.in()); +} + +// IDL list operation. + +CCS::Controller::ThermometerSeq * +Controller_impl:: +list() throw(CORBA::SystemException) +{ + // Create a new thermometer sequence. Because we know + // the number of elements we will put onto the sequence, + // we use the maximum constructor. + CCS::Controller::ThermometerSeq_var listv + = new CCS::Controller::ThermometerSeq(m_assets.size()); + listv->length(m_assets.size()); + + // Loop over the m_assets set and create a + // reference for each device. + CORBA::ULong count = 0; + AssetMap::iterator i; + for (i = m_assets.begin(); i != m_assets.end(); i++) + listv[count++] = make_dref(m_poa.in(), i->first); + return listv._retn(); +} + +// IDL change operation. + +void +Controller_impl:: +change( + const CCS::Controller::ThermostatSeq & tlist, + CORBA::Short delta +) throw(CORBA::SystemException, CCS::Controller::EChange) +{ + CCS::Controller::EChange ec; // Just in case we need it + + // We cannot add a delta value to a thermostat's temperature + // directly, so for each thermostat, we read the nominal + // temperature, add the delta value to it, and write + // it back again. + for (CORBA::ULong i = 0; i < tlist.length(); i++) { + if (CORBA::is_nil(tlist[i])) + continue; // Skip nil references + + // Read nominal temp and update it. + CCS::TempType tnom = tlist[i]->get_nominal(); + tnom += delta; + try { + tlist[i]->set_nominal(tnom); + } + catch (const CCS::Thermostat::BadTemp &bt) { + // If the update failed because the temperature + // is out of range, we add the thermostat's info + // to the errors sequence. + CORBA::ULong len = ec.errors.length(); + ec.errors.length(len + 1); + ec.errors[len].tmstat_ref = tlist[i]; + ec.errors[len].info = bt.details; + } + } + + // If we encountered errors in the above loop, + // we will have added elements to the errors sequence. + if (ec.errors.length() != 0) + throw ec; +} + +// IDL find operation + +void +Controller_impl:: +find(CCS::Controller::SearchSeq & slist) +throw(CORBA::SystemException) +{ + // Loop over input list and lookup each device. + CORBA::ULong listlen = slist.length(); + for (CORBA::ULong i = 0; i < listlen; i++) { + + AssetMap::iterator where; // Iterator for asset set + int num_found = 0; // Num matched per iteration + + // Assume we will not find a matching device. + slist[i].device = CCS::Thermometer::_nil(); + + // Work out whether we are searching by asset, + // model, or location. + CCS::Controller::SearchCriterion sc = slist[i].key._d(); + if (sc == CCS::Controller::ASSET) { + // Search for matching asset number. + where = m_assets.find(slist[i].key.asset_num()); + if (where != m_assets.end()) + slist[i].device = make_dref(m_poa.in(), where->first); + } else { + // Search for model or location string. + const char *search_str; + if (sc == CCS::Controller::LOCATION) + search_str = slist[i].key.loc(); + else + search_str = slist[i].key.model_desc(); + + // Find first matching device (if any). + where = find_if( + m_assets.begin(), m_assets.end(), + StrFinder(sc, search_str) + ); + + // While there are matches... + while (where != m_assets.end()) { + if (num_found == 0) { + // First match overwrites reference + // in search record. + slist[i].device = make_dref(m_poa.in(), where->first); + } else { + // Further matches each append a new + // element to the search sequence. + CORBA::ULong len = slist.length(); + slist.length(len + 1); + slist[len].key = slist[i].key; + slist[len].device = make_dref(m_poa.in(), where->first); + } + num_found++; + + // Find next matching device with this key. + where = find_if( + ++where, m_assets.end(), + StrFinder(sc, search_str) + ); + } + } + } +} + +//---------------------------------------------------------------- + +DeviceLocator_impl:: +DeviceLocator_impl(Controller_impl * ctrl) : m_ctrl(ctrl) +{ + // Intentionally empty +} + +PortableServer::Servant +DeviceLocator_impl:: +preinvoke( + const PortableServer::ObjectId & oid, + PortableServer::POA_ptr /* poa */, + const char * operation, + void * & /* cookie */, + CORBA_Environment & +) throw(CORBA::SystemException, PortableServer::ForwardRequest) +{ + // Convert object id into asset number. + CORBA::String_var oid_string; + try { + oid_string = PortableServer::ObjectId_to_string(oid); + } catch (const CORBA::BAD_PARAM &) { + throw CORBA::OBJECT_NOT_EXIST(); + } + + if (strcmp(oid_string.in(), Controller_oid) == 0) + return m_ctrl; + + istrstream istr(oid_string.in()); + CCS::AssetType anum; + istr >> anum; + if (istr.fail()) + throw CORBA::OBJECT_NOT_EXIST(); + + // Check whether the device is known. + if (!m_ctrl->exists(anum)) + throw CORBA::OBJECT_NOT_EXIST(); + + // Look at the object map to find out whether + // we have a servant in memory. + Thermometer_impl * servant; + ActiveObjectMap::iterator servant_pos = m_aom.find(anum); + if (servant_pos == m_aom.end()) { + // No servant in memory. If evictor queue is full, + // evict servant at head of queue. + if (m_eq.size() == MAX_EQ_SIZE) { + servant = m_eq.back(); + m_aom.erase(servant->m_anum); + m_eq.pop_back(); + delete servant; + } + // Instantiate correct type of servant. + char buf[32]; + assert(ICP_get(anum, "model", buf, sizeof(buf)) == 0); + if (strcmp(buf, "Sens-A-Temp") == 0) + servant = new Thermometer_impl(anum); + else + servant = new Thermostat_impl(anum); + } else { + // Servant already in memory. + servant = *(servant_pos->second); // Remember servant + m_eq.erase(servant_pos->second); // Remove from queue + + // If operation is "remove", also remove entry from + // active object map -- the object is about to be deleted. + if (strcmp(operation, "remove") == 0) + m_aom.erase(servant_pos); + } + + // We found a servant, or just instantiated it. + // If the operation is not a remove, move + // the servant to the tail of the evictor queue + // and update its queue position in the map. + if (strcmp(operation, "remove") != 0) { + m_eq.push_front(servant); + m_aom[anum] = m_eq.begin(); + } + + return servant; +} + +//---------------------------------------------------------------- + +int +main(int argc, char * argv[]) +{ + CORBA::ORB_var orb; + + try { + // Initialize orb + orb = CORBA::ORB_init(argc, argv); + + // Get reference to Root POA. + CORBA::Object_var obj + = orb->resolve_initial_references("RootPOA"); + PortableServer::POA_var poa + = PortableServer::POA::_narrow(obj.in()); + + // Get POA manager + PortableServer::POAManager_var poa_mgr = poa->the_POAManager(); + + // Create a policy list. We use persistent objects with + // user-assigned IDs, and explicit activation. + CORBA::PolicyList policy_list; + policy_list.length(6); + policy_list[0] = poa->create_lifespan_policy( + PortableServer::TRANSIENT // REVISIT + ); + policy_list[1] = poa->create_id_assignment_policy( + PortableServer::USER_ID + ); + policy_list[2] = poa->create_implicit_activation_policy( + PortableServer::NO_IMPLICIT_ACTIVATION + ); + policy_list[3] = poa->create_request_processing_policy( + PortableServer::USE_SERVANT_MANAGER + ); + policy_list[4] = poa->create_servant_retention_policy( + PortableServer::NON_RETAIN + ); + policy_list[5] = poa->create_thread_policy( + PortableServer::SINGLE_THREAD_MODEL + ); + + // Create a POA for all CCS elements. + PortableServer::POA_var ccs_poa + = poa->create_POA("CCS_POA", poa_mgr.in(), policy_list); + + // Create a controller and set static m_ctrl member + // for thermostats and thermometers. + Controller_impl ctrl_servant(ccs_poa.in(), "/tmp/CCS_assets"); + Thermometer_impl::m_ctrl = &ctrl_servant; + + // Create a reference for the controller and + // create the corresponding CORBA object. + PortableServer::ObjectId_var oid + = PortableServer::string_to_ObjectId(Controller_oid); + CORBA::Object_var ctrl + = ccs_poa->create_reference_with_id( + oid.in(), "IDL:acme.com/CCS/Controller:1.0" + ); + + // Get reference to initial naming context. + CosNaming::NamingContext_var inc + = resolve_init( + orb.in(), "NameService" + ); + + // Attempt to create CCS context. + CosNaming::Name n; + n.length(1); + n[0].id = CORBA::string_dup("CCS"); + try { + CosNaming::NamingContext_var nc + = inc->bind_new_context(n); + } catch (const CosNaming::NamingContext::AlreadyBound &) { + // Fine, CCS context already exists. + } + + // Force binding of controller reference to make + // sure it is always up-to-date. + n.length(2); + n[1].id = CORBA::string_dup("Controller"); + inc->rebind(n, ctrl.in()); + + // Instantiate the servant locator for devices. + DeviceLocator_impl my_locator(&ctrl_servant); + PortableServer::ServantManager_var locator + = my_locator._this(); + + // Set servant locator. + ccs_poa->set_servant_manager(locator.in()); + + // Activate the POA manager. + poa_mgr->activate(); + + // Accept requests + orb->run(); + } + catch (const CORBA::Exception & e) { + cerr << "Uncaught CORBA exception: " << e << endl; + return 1; + } + catch (...) { + assert(0); // Uncaught exception, dump core + } + return 0; +} diff --git a/TAO/examples/Advanced/ch_18/server.h b/TAO/examples/Advanced/ch_18/server.h new file mode 100644 index 00000000000..5eef5fe6300 --- /dev/null +++ b/TAO/examples/Advanced/ch_18/server.h @@ -0,0 +1,238 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_18 +// +// = FILENAME +// server.h +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#ifndef server_HH_ +#define server_HH_ + +#include "CCSS.h" +#include "icp.h" +#include +#include +//#include +//#include + + +class Controller_impl; + +class Thermometer_impl : public virtual POA_CCS::Thermometer { +public: + // CORBA attributes + virtual CCS::ModelType model() + throw(CORBA::SystemException); + virtual CCS::AssetType asset_num() + throw(CORBA::SystemException); + virtual CCS::TempType temperature() + throw(CORBA::SystemException); + virtual CCS::LocType location() + throw(CORBA::SystemException); + virtual void location(const char *loc) + throw(CORBA::SystemException); + virtual void remove() + throw(CORBA::SystemException); + + // Constructor & destructor + Thermometer_impl(CCS::AssetType anum); + virtual ~Thermometer_impl(); + + static Controller_impl * m_ctrl; // My controller + const CCS::AssetType m_anum; // My asset number + +private: + // Helper functions + CCS::ModelType get_model(); + CCS::TempType get_temp(); + CCS::LocType get_loc(); + void set_loc(const char * new_loc); + + // Copy and assignment not supported + Thermometer_impl(const Thermometer_impl &); + void operator=(const Thermometer_impl &); +}; + +class Thermostat_impl : + public virtual POA_CCS::Thermostat, + public virtual Thermometer_impl { +public: + // CORBA operations + virtual CCS::TempType get_nominal() + throw(CORBA::SystemException); + virtual CCS::TempType set_nominal( + CCS::TempType new_temp + ) throw( + CORBA::SystemException, + CCS::Thermostat::BadTemp + ); + + // Constructor and destructor + Thermostat_impl(CCS::AssetType anum); + virtual ~Thermostat_impl(); + +private: + // Helper functions + CCS::TempType get_nominal_temp(); + CCS::TempType set_nominal_temp(CCS::TempType new_temp) + throw(CCS::Thermostat::BadTemp); + + // Copy and assignment not supported + Thermostat_impl(const Thermostat_impl &); + void operator=(const Thermostat_impl &); +}; + +class Controller_impl : public virtual POA_CCS::Controller { +public: + // CORBA operations + virtual CCS::Controller::ThermometerSeq * + list() throw(CORBA::SystemException); + virtual void + find(CCS::Controller::SearchSeq & slist) + throw(CORBA::SystemException); + virtual void + change( + const CCS::Controller::ThermostatSeq & tlist, + CORBA::Short delta + ) throw( + CORBA::SystemException, + CCS::Controller::EChange + ); + virtual CCS::Thermometer_ptr + create_thermometer( + CCS::AssetType anum, + const char* loc + ) throw( + CORBA::SystemException, + CCS::Controller::DuplicateAsset + ); + virtual CCS::Thermostat_ptr + create_thermostat( + CCS::AssetType anum, + const char* loc, + CCS::TempType temp + ) throw( + CORBA::SystemException, + CCS::Controller::DuplicateAsset, + CCS::Thermostat::BadTemp + ); + + // Constructor and destructor + Controller_impl( + PortableServer::POA_ptr poa, + const char * asset_file + ) throw(int); + virtual ~Controller_impl(); + + // Helper functions to allow access to the object map + void add_impl( + CCS::AssetType anum, + Thermometer_impl * tip + ); + void remove_impl(CCS::AssetType anum); + bool exists(CCS::AssetType anum); + +private: + // Map of existing assets. The servant pointer is null + // the corresponding servant is not in memory. + typedef map AssetMap; + AssetMap m_assets; + + // POA for thermometers and thermostats + PortableServer::POA_var m_poa; + + // Name of asset number file + CORBA::String_var m_asset_file; + + // Copy and assignment not supported + Controller_impl(const Controller_impl &); + void operator=(const Controller_impl &); + + // Function object for the find_if algorithm to search for + // devices by location and model string. + class StrFinder { + public: + StrFinder( + CCS::Controller::SearchCriterion sc, + const char * str + ) : m_sc(sc), m_str(str) {} + bool operator()( + pair & p + ) const + { + char buf[32]; + switch (m_sc) { + case CCS::Controller::LOCATION: + ICP_get(p.first, "location", buf, sizeof(buf)); + break; + case CCS::Controller::MODEL: + ICP_get(p.first, "model", buf, sizeof(buf)); + break; + default: + assert(0); // Precondition violation + } + return strcmp(buf, m_str) == 0; + } + private: + CCS::Controller::SearchCriterion m_sc; + const char * m_str; + }; +}; + +class DeviceLocator_impl : + public virtual POA_PortableServer::ServantLocator { +public: + DeviceLocator_impl(Controller_impl * ctrl); + + virtual PortableServer::Servant + preinvoke( + const PortableServer::ObjectId & oid, + PortableServer::POA_ptr poa, + const char * operation, + void * & cookie, + CORBA_Environment & + ) throw( + CORBA::SystemException, + PortableServer::ForwardRequest); + virtual void + postinvoke( + const PortableServer::ObjectId & /* oid */, + PortableServer::POA_ptr /* poa */, + const char * /* operation */, + void * /* cookie */, + PortableServer::Servant /* servant */, + CORBA_Environment & + ) throw(CORBA::SystemException) {} + +private: + Controller_impl * m_ctrl; + + typedef list EvictorQueue; + typedef map + ActiveObjectMap; + + static const unsigned int MAX_EQ_SIZE = 100; + EvictorQueue m_eq; + ActiveObjectMap m_aom; + + // Copy and assignment not supported + DeviceLocator_impl(const DeviceLocator_impl &); + void operator=(const DeviceLocator_impl &); +}; + +#endif diff --git a/TAO/examples/Advanced/ch_3/CHANGES b/TAO/examples/Advanced/ch_3/CHANGES new file mode 100644 index 00000000000..4185ef533a8 --- /dev/null +++ b/TAO/examples/Advanced/ch_3/CHANGES @@ -0,0 +1,47 @@ +$Id$ + +Changelog for chapter 3 example in "Advanced CORBA Programming +with C++" by Michi Henning and Steve Vinoski, Copyright 1999, +Addison-Wesley, Reading, MA. The following changes have been made +to the book's source code to make the example work with TAO and +with various platforms and compilers. + +______________________________________________________________________________ +ESSENTIAL CHANGES: + 1. changed filenames .cc to .cpp and .hh h, and modified #includes in + client.cpp server.cpp and server.h appropriately. + + 2. a) changed #include "time.h" to #include "timeC.h" in client.cpp + + b) Moved standard #includes below local #includes, and commented-out + unnecessary #includes to avoid warnings and errors (g++) + -client.cpp now reads: + #include "timeC.h" + #include + // #include + -server.cpp now reads: + #include "server.h" + // #include + // #include + +______________________________________________________________________________ +ADDITIONAL CHANGES: + 3. added .in() to _var type parameters + -3 times in client.cpp for calls to is_nil() and _narrow() + -3 times in main() in server.cpp for calls to _narrow(), + object_to_string, and << + + + + + + + + + + + + + + + diff --git a/TAO/examples/Advanced/ch_3/Makefile b/TAO/examples/Advanced/ch_3/Makefile new file mode 100644 index 00000000000..4fb5a0eb2db --- /dev/null +++ b/TAO/examples/Advanced/ch_3/Makefile @@ -0,0 +1,71 @@ +#---------------------------------------------------------------------------- +# +# $Id$ +# +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +ifndef TAO_ROOT + TAO_ROOT = $(ACE_ROOT)/TAO +endif # ! TAO_ROOT + + + +LDLIBS = -lTAO +IDL_SRC = timeC.cpp timeS.cpp +IDL_HDR = timeC.h timeS.h + +PROG_SRCS = \ + client.cpp \ + server.cpp \ + +SRC = $(IDL_SRC) $(PROG_SRCS) + +SIMPLE_CLT_OBJS = \ + timeC.o \ + timeS.o \ + client.o + +SIMPLE_SVR_OBJS = \ + timeC.o \ + timeS.o \ + server.o + + +BIN = server \ + client +BUILD = $(BIN) + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(ACE_ROOT)/include/makeinclude/macros.GNU +include $(TAO_ROOT)/rules.tao.GNU +include $(ACE_ROOT)/include/makeinclude/rules.common.GNU +include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU +include $(ACE_ROOT)/include/makeinclude/rules.local.GNU +include $(TAO_ROOT)/taoconfig.mk + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- +.PRECIOUS: timeC.cpp timeC.i timeC.h +.PRECIOUS: timeS.cpp timeS.i timeS.h +.PRECIOUS: timeS_T.cpp timeS_T.i timeS_T.h + +server: $(addprefix $(VDIR),$(SIMPLE_SVR_OBJS)) + $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS) $(POSTLINK) + +client: $(addprefix $(VDIR),$(SIMPLE_CLT_OBJS)) + $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS) $(POSTLINK) + +realclean: clean + -/bin/$(RM) -rf timeC.* timeS.* timeS_T.* time.h + +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. diff --git a/TAO/examples/Advanced/ch_3/README b/TAO/examples/Advanced/ch_3/README new file mode 100644 index 00000000000..e74eeb9bdf1 --- /dev/null +++ b/TAO/examples/Advanced/ch_3/README @@ -0,0 +1,42 @@ +$Id$ + +Chapter 3 example. +______________________________________________________________________________ +This example been taken from the book "Advanced CORBA Programming with C++" +by Michi Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +MA. To make the examples work with TAO, some minor modifications to the +source code have been made, with permission, by Mike Moran . +All of these changes are documented in the file CHANGES, in this directory. +______________________________________________________________________________ + + +Summary: + This is the simple time server given in chapter 3 of the book. + There is a server process which holds a servant object which can return + the current Greenwich time, and a client process which can acess this + object. + +Building: + This example must be built with native C++ exceptions, and with an ACE/TAO + build with exceptions. Make sure to use TAO_FLAG Ge=0 to ensure + that CORBA::Environment variables are not created in the IDL generated + stubs and skeletons. + + With GNU make, simply type + + % make exceptions=1 + + to create the executable server and client + +server: + The server takes no parameters nor command line options and returns an + IOR to stdout. The server then waits infinitely for clients requests. + +client: + The client takes an IOR from the command line, prints out the current + time, and terminates. + +run_test.pl: + This is currently a UNIX only script! It starts up the server, redirecting + stdout to a file, then passes the file's contents to the command line of + the client. After the client terminates, the server is killed. diff --git a/TAO/examples/Advanced/ch_3/client.cpp b/TAO/examples/Advanced/ch_3/client.cpp new file mode 100644 index 00000000000..cfeffd08215 --- /dev/null +++ b/TAO/examples/Advanced/ch_3/client.cpp @@ -0,0 +1,67 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_3 +// +// = FILENAME +// client.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + +#include "timeC.h" +#include +//#include + +int +main(int argc, char * argv[]) +{ + try { + // Check arguments + if (argc != 2) { + cerr << "Usage: client IOR_string" << endl; + throw 0; + } + + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + // Destringify argv[1] + CORBA::Object_var obj = orb->string_to_object(argv[1]); + if (CORBA::is_nil(obj.in())) { + cerr << "Nil Time reference" << endl; + throw 0; + } + + // Narrow + Time_var tm = Time::_narrow(obj.in()); + if (CORBA::is_nil(tm.in())) { + cerr << "Argument is not a Time reference" << endl; + throw 0; + } + + // Get time + TimeOfDay tod = tm->get_gmt(); + cout << "Time in Greenwich is " + << setw(2) << setfill('0') << tod.hour << ":" + << setw(2) << setfill('0') << tod.minute << ":" + << setw(2) << setfill('0') << tod.second << endl; + } + catch (const CORBA::Exception &) { + cerr << "Uncaught CORBA exception" << endl; + return 1; + } + catch (...) { + return 1; + } + return 0; +} diff --git a/TAO/examples/Advanced/ch_3/run_test.pl b/TAO/examples/Advanced/ch_3/run_test.pl new file mode 100755 index 00000000000..74c52a910be --- /dev/null +++ b/TAO/examples/Advanced/ch_3/run_test.pl @@ -0,0 +1,54 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "../../../../bin"; + +require ACEutils; +require Process; + +$status = 0; +$iorfile = "chapter_test.ior"; +unlink $iorfile; + + + +# Hacked call +$server = Process::Create ("exec ".$EXEPREFIX."server".$EXE_EXT.">$iorfile", + ""); +# Proper call +#$server = Process::Create ($EXEPREFIX."server".$EXE_EXT, ">$iorfile"); + +if (ACE::waitforfile_timed ($iorfile, 15) == -1) { + print STDERR "ERROR: timedout waiting for file <$iorfile>\n"; + $server->Kill (); $server->TimedWait (1); + exit 1; +} + +open(ior_handle, "$iorfile"); +$ior_content = ; + +$client = Process::Create($EXEPREFIX."client$EXE_EXT", "$ior_content"); + +if ($client->TimedWait (60) == -1) { + print STDERR "ERROR: client timedout\n"; + $status = 1; + $client->Kill (); $client->TimedWait (1); +} + + + + +$server->Terminate (); +if ($server->TimedWait (5) == -1) { + print STDERR "ERROR: cannot terminate the server\n"; + $server->Kill (); $server->TimedWait (1); + $status = 1; +} + +unlink $iorfile; + +exit $status; diff --git a/TAO/examples/Advanced/ch_3/server.cpp b/TAO/examples/Advanced/ch_3/server.cpp new file mode 100644 index 00000000000..d095f4e2d88 --- /dev/null +++ b/TAO/examples/Advanced/ch_3/server.cpp @@ -0,0 +1,89 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_3 +// +// = FILENAME +// server.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + +#include "server.h" +//#include +//#include + + +TimeOfDay +Time_impl:: +get_gmt() throw(CORBA::SystemException) +{ + time_t time_now = time(0); + struct tm * time_p = gmtime(&time_now); + + TimeOfDay tod; + tod.hour = time_p->tm_hour; + tod.minute = time_p->tm_min; + tod.second = time_p->tm_sec; + + return tod; +} +// $Id$ +// Changelog for Henning and Vinoski's chapter 18 example +// ______________________________________________________ + +//----------------------------------------------------------------------------- + +int +main(int argc, char * argv[]) +{ + try { + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + // Get reference to Root POA. + CORBA::Object_var obj + = orb->resolve_initial_references("RootPOA"); + PortableServer::POA_var poa + = PortableServer::POA::_narrow(obj.in()); + + // Activate POA manager + PortableServer::POAManager_var mgr + = poa->the_POAManager(); + mgr->activate(); + + // Create an object + Time_impl time_servant; + + // Write its stringified reference to stdout + Time_var tm = time_servant._this(); + CORBA::String_var str = orb->object_to_string(tm.in()); + cout << str.in() << endl; + + // Accept requests + orb->run(); + } + catch (const CORBA::Exception &) { + cerr << "Uncaught CORBA exception" << endl; + return 1; + } + return 0; +} + + + + + + + + diff --git a/TAO/examples/Advanced/ch_3/server.h b/TAO/examples/Advanced/ch_3/server.h new file mode 100644 index 00000000000..e7dfcd309c8 --- /dev/null +++ b/TAO/examples/Advanced/ch_3/server.h @@ -0,0 +1,31 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_3 +// +// = FILENAME +// server.h +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + +#ifndef server_HH_ +#define server_HH_ + +#include "timeS.h" + +class Time_impl : public virtual POA_Time { +public: + virtual TimeOfDay get_gmt() throw(CORBA::SystemException); +}; + +#endif diff --git a/TAO/examples/Advanced/ch_3/time.idl b/TAO/examples/Advanced/ch_3/time.idl new file mode 100644 index 00000000000..a8e7e7080ac --- /dev/null +++ b/TAO/examples/Advanced/ch_3/time.idl @@ -0,0 +1,31 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_3 +// +// = FILENAME +// time.idl +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + +struct TimeOfDay { + short hour; // 0 - 23 + short minute; // 0 - 59 + short second; // 0 - 59 +}; + +interface Time { + TimeOfDay get_gmt(); +}; + diff --git a/TAO/examples/Advanced/ch_8_and_10/CCS.idl b/TAO/examples/Advanced/ch_8_and_10/CCS.idl new file mode 100644 index 00000000000..7ab254d6eec --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/CCS.idl @@ -0,0 +1,88 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_8_and_10 +// +// = FILENAME +// CCS.idl +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + +#pragma prefix "acme.com" + +module CCS { + typedef unsigned long AssetType; + typedef string ModelType; + typedef short TempType; + typedef string LocType; + + interface Thermometer { + readonly attribute ModelType model; + readonly attribute AssetType asset_num; + readonly attribute TempType temperature; + attribute LocType location; + }; + + interface Thermostat : Thermometer { + struct BtData { + TempType requested; + TempType min_permitted; + TempType max_permitted; + string error_msg; + }; + exception BadTemp { BtData details; }; + + TempType get_nominal(); + TempType set_nominal(in TempType new_temp) + raises(BadTemp); + }; + + interface Controller { + typedef sequence ThermometerSeq; + typedef sequence ThermostatSeq; + + enum SearchCriterion { ASSET, LOCATION, MODEL }; + + union KeyType switch(SearchCriterion) { + case ASSET: + AssetType asset_num; + case LOCATION: + LocType loc; + case MODEL: + ModelType model_desc; + }; + + struct SearchType { + KeyType key; + Thermometer device; + }; + typedef sequence SearchSeq; + + struct ErrorDetails { + Thermostat tmstat_ref; + Thermostat::BtData info; + }; + typedef sequence ErrSeq; + + exception EChange { + ErrSeq errors; + }; + + ThermometerSeq list(); + void find(inout SearchSeq slist); + void change( + in ThermostatSeq tlist, in short delta + ) raises(EChange); + }; +}; diff --git a/TAO/examples/Advanced/ch_8_and_10/CHANGES b/TAO/examples/Advanced/ch_8_and_10/CHANGES new file mode 100644 index 00000000000..b1454a1983d --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/CHANGES @@ -0,0 +1,51 @@ +$Id$ + +Changelog for chapter 8 and 10 example in "Advanced CORBA +Programming with C++" by Michi Henning and Steve Vinoski, +Copyright 1999, Addison-Wesley, Reading, MA. The following +changes have been made to the book's source code to make the +example work with TAO and with various platforms and compilers. + +_______________________________________________________________________________ +ESSENTIAL CHANGES: + 1. Changed filenames from .cc to .cpp and .hh to.h, + and modified #includes appropriatly + + 2. a) Unnecessary standard includes of and must + be removed or moved to follow the local includes in + server.h, server.cpp, client.cpp, and icp.cpp. + + b) The following files may need their includes further rearranged + to avoid warnings and errors (g++). The following orderings + seem to work fine: + -server.cpp: "server.h", , "icp.h" + -server.h: "CCSS.h", + + 3. removed if 0 code surrounding + operator<<(ostream & os, const CCS::Controller::EChange & ec) + definition in server.cpp and client.cpp. + +_______________________________________________________________________________ +ADDITIONAL CHANGES: + 4. Added .in() to _var parameters wherever needed: + -client.cpp: + -4 changes in operator<<(ostream & os, CCS::Thermometer_ptr t) + -6 changes in main(): 5 calls to is_nil(), 1 call to _narrow + -2 additions in main() of .inout() to _var parameters of set_temp(). + Note: .inout() is functionally the same as .in() in this case + + -server.cpp: + 3 changes in main() + +_______________________________________________________________________________ +TO DO: + -discrepancy in temperatures in my output vs. sample output + in book. +_____________________________________________________ + + + + + + + diff --git a/TAO/examples/Advanced/ch_8_and_10/Makefile b/TAO/examples/Advanced/ch_8_and_10/Makefile new file mode 100644 index 00000000000..5557a433044 --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/Makefile @@ -0,0 +1,86 @@ +#---------------------------------------------------------------------------- +# +# $Id$ +# +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- +# Local macros +#---------------------------------------------------------------------------- + +ifndef TAO_ROOT + TAO_ROOT = $(ACE_ROOT)/TAO +endif + +LDLIBS = -lTAO +IDL_SRC = CCSC.cpp CCSS.cpp +IDL_HDR = CCSC.h CCSS.h + +PROG_SRCS = \ + client.cpp \ + server.cpp \ + icp.cpp + +SRC = $(IDL_SRC) $(PROG_SRCS) + +SIMPLE_CLT_OBJS = \ + CCSC.o \ + CCSS.o \ + client.o + +SIMPLE_SVR_OBJS = \ + CCSC.o \ + CCSS.o \ + server.o \ + icp.o + + +BIN = server \ + client +BUILD = $(BIN) +VLDLIBS = $(LDLIBS:%=%$(VAR)) +VBIN = $(BIN:%=%$(VAR)) + +#---------------------------------------------------------------------------- +# Include macros and targets +#---------------------------------------------------------------------------- + +include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU +include $(ACE_ROOT)/include/makeinclude/macros.GNU +include $(TAO_ROOT)/rules.tao.GNU +include $(ACE_ROOT)/include/makeinclude/rules.common.GNU +include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU +include $(ACE_ROOT)/include/makeinclude/rules.local.GNU +include $(TAO_ROOT)/taoconfig.mk + +#---------------------------------------------------------------------------- +# Local targets +#---------------------------------------------------------------------------- +LDFLAGS += -L$(TAO_ROOT)/orbsvcs/orbsvcs -L$(TAO_ROOT)/tao -L$(TAO_ROOT)/orbsvcs/Naming_Service +CPPFLAGS += -I$(TAO_ROOT)/orbsvcs + +.PRECIOUS: CCSC.cpp CCSC.i CCSC.h +.PRECIOUS: CCSS.cpp CCSS.i CCSS.h +.PRECIOUS: CCSS_T.cpp CCSS_T.i CCSS_T.h + +override TAO_IDLFLAGS += -hc .hh -hs S.hh -hT S_T.hh \ + -cs C.cc -ci C.i \ + -ss S.cc -sT S_T.cc +CCFLAGS += -fimplicit-templates -frtti -O0 + +$(IDL_SRC): CCS.idl + $(TAO_ROOT)/TAO_IDL/tao_idl CCS.idl -hc .h -hs S.h -hT S_T.h \ + -cs C.cpp \ + -ss S.cpp -sT S_T.cpp +server: $(addprefix $(VDIR),$(SIMPLE_SVR_OBJS)) + $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS) $(POSTLINK) + +client: $(addprefix $(VDIR),$(SIMPLE_CLT_OBJS)) + $(LINK.cc) $(LDFLAGS) -o $@ $^ $(VLDLIBS) $(POSTLINK) + +realclean: clean + -/bin/$(RM) -rf CCSC.* CCSS.* CCSS_T.* CCS.h + +# DO NOT DELETE THIS LINE -- g++dep uses it. +# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. + diff --git a/TAO/examples/Advanced/ch_8_and_10/README b/TAO/examples/Advanced/ch_8_and_10/README new file mode 100644 index 00000000000..6b44902f1f6 --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/README @@ -0,0 +1,40 @@ +$Id$ + +Chapters 8 and 10 example. +______________________________________________________________________________ +This example been taken from the book "Advanced CORBA Programming with C++" +by Michi Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +MA. To make the examples work with TAO, some minor modifications to the +source code have been made, with permission, by Mike Moran . +All of these changes are documented in the file CHANGES, in this directory. +______________________________________________________________________________ + + +Summary: + This is the most basic version of the climate control system presented + throughout the book. The client is presented in chapter 8 and the + server in chapter 10. + +Building: + This example must be built with native C++ exceptions, and with an ACE/TAO + build with exceptions. Make sure to use TAO_FLAG Ge=0 to ensure + that the IDL generated code uses c++ exceptions rather than creating + CORBA_Environment variables. + + With GNU make, simply type + % make exceptions=1 + to create the executable server and client. + +server: + The server takes no parameters nor command line options and returns an + IOR to stdout. The server then waits infinitely for clients requests. + +client: + The client takes an IOR from the command line, narrows this to a + controller reference, makes several remote calls on this controller, and + finally terminates. + +run_test.pl: + This is currently a UNIX only script! It starts up the server, redirecting + stdout to a file, then passes the file's contents to the command line of + the client. After the client terminates, the server is killed. \ No newline at end of file diff --git a/TAO/examples/Advanced/ch_8_and_10/client.cpp b/TAO/examples/Advanced/ch_8_and_10/client.cpp new file mode 100644 index 00000000000..79a848ae226 --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/client.cpp @@ -0,0 +1,265 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_8_and_10 +// +// = FILENAME +// client.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#include "CCS.h" // ORB-specific +//#include + +// Show the details for a thermometer or thermostat. +static ostream & +operator<<(ostream & os, CCS::Thermometer_ptr t) +{ + // Check for nil. + if (CORBA::is_nil(t)) { + os << "Cannot show state for nil reference." << endl; + return os; + } + + // Try to narrow and print what kind of device it is. + CCS::Thermostat_var tmstat = CCS::Thermostat::_narrow(t); + os << (CORBA::is_nil(tmstat.in()) ? "Thermometer:" : "Thermostat:") + << endl; + + // Show attribute values. + CCS::ModelType_var model = t->model(); + CCS::LocType_var location = t->location(); + os << "\tAsset number: " << t->asset_num() << endl; + os << "\tModel : " << model.in() << endl; + os << "\tLocation : " << location.in() << endl; + os << "\tTemperature : " << t->temperature() << endl; + + // If device is a thermostat, show nominal temperature. + if (!CORBA::is_nil(tmstat.in())) + os << "\tNominal temp: " << tmstat->get_nominal() << endl; + return os; +} + +//---------------------------------------------------------------- + +// Show the information in a BtData struct. + +static ostream & +operator<<(ostream & os, const CCS::Thermostat::BtData & btd) +{ + os << "CCS::Thermostat::BtData details:" << endl; + os << "\trequested : " << btd.requested << endl; + os << "\tmin_permitted: " << btd.min_permitted << endl; + os << "\tmax_permitted: " << btd.max_permitted << endl; + os << "\terror_msg : " << btd.error_msg << endl; + return os; +} + +//---------------------------------------------------------------- + +// Loop over the sequence of records in an EChange exception and +// show the details of each record. + +static ostream & +operator<<(ostream & os, const CCS::Controller::EChange & ec) +{ + for (CORBA::ULong i = 0; i < ec.errors.length(); i++) { + os << "Change failed:" << endl; + os << ec.errors[i].tmstat_ref.in(); // Overloaded << + os << ec.errors[i].info << endl; // Overloaded << + } + return os; +} + +//---------------------------------------------------------------- + +// Generic ostream inserter for exceptions. Inserts the exception +// name, if available, and the repository ID otherwise. + +// #if 0 // This inserter may or may not be needed for your ORB. + +static ostream & +operator<<(ostream & os, const CORBA::Exception & e) +{ + CORBA::Any tmp; + tmp <<= e; + + CORBA::TypeCode_var tc = tmp.type(); + const char * p = tc->name(); + if (*p != '\0') + os << p; + else + os << tc->id(); + return os; +} + +// #endif + +//---------------------------------------------------------------- + +// Change the temperature of a thermostat. + +static void +set_temp(CCS::Thermostat_ptr tmstat, CCS::TempType new_temp) +{ + if (CORBA::is_nil(tmstat)) // Don't call via nil reference + return; + + CCS::AssetType anum = tmstat->asset_num(); + try { + cout << "Setting thermostat " << anum + << " to " << new_temp << " degrees." << endl; + CCS::TempType old_nominal = tmstat->set_nominal(new_temp); + cout << "Old nominal temperature was: " + << old_nominal << endl; + cout << "New nominal temperature is: " + << tmstat->get_nominal() << endl; + } catch (const CCS::Thermostat::BadTemp & bt) { + cerr << "Setting of nominal temperature failed." << endl; + cerr << bt.details << endl; // Overloaded << + } +} + +//---------------------------------------------------------------- + +int +main(int argc, char * argv[]) +{ + try { + // Initialize the ORB + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + // Check arguments + if (argc != 2) { + cerr << "Usage: client IOR_string" << endl; + throw 0; + } + + // Get controller reference from argv + // and convert to object. + CORBA::Object_var obj = orb->string_to_object(argv[1]); + if (CORBA::is_nil(obj.in())) { + cerr << "Nil controller reference" << endl; + throw 0; + } + + // Try to narrow to CCS::Controller. + CCS::Controller_var ctrl; + try { + ctrl = CCS::Controller::_narrow(obj.in()); + } catch (const CORBA::SystemException & se) { + cerr << "Cannot narrow controller reference: " + << se << endl; + throw 0; + } + if (CORBA::is_nil(ctrl.in())) { + cerr << "Wrong type for controller ref." << endl; + throw 0; + } + + // Get list of devices + CCS::Controller::ThermometerSeq_var list = ctrl->list(); + + // Show number of devices. + CORBA::ULong len = list->length(); + cout << "Controller has " << len << " device"; + if (len != 1) + cout << "s"; + cout << "." << endl; + + // If there are no devices at all, we are finished. + if (len == 0) + return 0; + + // Show details for each device. + for (CORBA::ULong i = 0; i < list->length(); i++) + cout << list[i].in(); + cout << endl; + + // Change the location of first device in the list + CCS::AssetType anum = list[0]->asset_num(); + cout << "Changing location of device " + << anum << "." << endl; + list[0]->location("Earth"); + // Check that the location was updated + cout << "New details for device " + << anum << " are:" << endl; + cout << list[0] << endl; + + // Find first thermostat in list. + CCS::Thermostat_var tmstat; + for ( CORBA::ULong i = 0; + i < list->length() && CORBA::is_nil(tmstat.in()); + i++) { + tmstat = CCS::Thermostat::_narrow(list[i]); + } + + // Check that we found a thermostat on the list. + if (CORBA::is_nil(tmstat.in())) { + cout << "No thermostat devices in list." << endl; + } else { + // Set temperature of thermostat to + // 50 degrees (should work). + set_temp(tmstat.inout(), 50); + cout << endl; + + // Set temperature of thermostat to + // -10 degrees (should fail). + set_temp(tmstat.inout(), -10); + } + + // Look for device in Rooms Earth and HAL. This must + // locate at least one device because we earlier changed + // the location of the first device to Room Earth. + cout << "Looking for devices in Earth and HAL." << endl; + CCS::Controller::SearchSeq ss; + ss.length(2); + ss[0].key.loc(CORBA::string_dup("Earth")); + ss[1].key.loc(CORBA::string_dup("HAL")); + ctrl->find(ss); + + // Show the devices found in that room. + for (CORBA::ULong i = 0; i < ss.length(); i++) + cout << ss[i].device.in(); // Overloaded << + cout << endl; + + // Increase the temperature of all thermostats + // by 40 degrees. First, make a new list (tss) + // containing only thermostats. + cout << "Increasing thermostats by 40 degrees." << endl; + CCS::Controller::ThermostatSeq tss; + for (CORBA::ULong i = 0; i < list->length(); i++) { + tmstat = CCS::Thermostat::_narrow(list[i]); + if (CORBA::is_nil(tmstat.in())) + continue; // Skip thermometers + len = tss.length(); + tss.length(len + 1); + tss[len] = tmstat; + } + + // Try to change all thermostats. + try { + ctrl->change(tss, 40); + } catch (const CCS::Controller::EChange & ec) { + cerr << ec; // Overloaded << + } + } catch (const CORBA::Exception & e) { + cerr << "Uncaught CORBA exception: " << e << endl; + return 1; + } catch (...) { + return 1; + } + return 0; +} diff --git a/TAO/examples/Advanced/ch_8_and_10/icp.cpp b/TAO/examples/Advanced/ch_8_and_10/icp.cpp new file mode 100644 index 00000000000..968190249c7 --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/icp.cpp @@ -0,0 +1,300 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_8_and_10 +// +// = FILENAME +// icp.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#include +#include +#include +//#include +#include "icp.h" + +//---------------------------------------------------------------- + +enum DeviceType { thermometer, thermostat }; + +struct DeviceState { // State for a device + DeviceType type; + const char * model; + string location; + short nominal_temp; // For thermostats only +}; +typedef map StateMap; + +//---------------------------------------------------------------- + +const size_t MAXSTR = 32; // Max len of string including NUL + +const short MIN_TEMP = 40; // 40 F == 4.44 C +const short MAX_TEMP = 90; // 90 F == 32.22 C +const short DFLT_TEMP = 68; // 68 F == 20.00 C + +static StateMap dstate; // Map of known devices + +//---------------------------------------------------------------- + +// ICP_online() simulates adding a new device to the network by +// adding it to the dstate map. +// +// For this simple simulation, devices with odd asset numbers +// are thermometers and devices with even asset numbers +// are thermostats. +// +// Thermostats get an initial nominal temperature of DFLT_TEMP. +// The location string is intentionally left blank because it +// must be programmed by the controller after putting the device +// on-line (as should be the nominal temperature). +// +// If a device with the specified ID is already on-line, the +// return value is -1. A zero return value indicates success. + +extern "C" +int +ICP_online(unsigned long id) +{ + // Look for id in state map. + StateMap::iterator pos = dstate.find(id); + if (pos != dstate.end()) + return -1; // Already exists + + // Fill in state. + DeviceState ds; + ds.type = (id % 2) ? thermometer : thermostat; + ds.model = (ds.type == thermometer) + ? "Sens-A-Temp" : "Select-A-Temp"; + ds.nominal_temp = DFLT_TEMP; + + // Insert new device into map + dstate[id] = ds; + + return 0; +} + +//---------------------------------------------------------------- + +// ICP_offline() simulates removing a device from the network by +// removing it from the dstate map. If the device isn't known, the +// return value is -1. A zero return value indicates success. + +extern "C" +int +ICP_offline(unsigned long id) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + dstate.erase(id); + return 0; +} + +//---------------------------------------------------------------- + +// vary_temp() simulates the variation in actual temperature +// around a thermostat. The function randomly varies the +// temperature as a percentage of calls as follows: +// +// 3 degrees too cold: 5% +// 3 degrees too hot: 5% +// 2 degrees too cold: 10% +// 2 degrees too hot: 10% +// 1 degree too cold: 15% +// 1 degree too hot: 15% +// exact temperature: 40% + +static +short +vary_temp(short temp) +{ + long r = lrand48() % 50; + long delta; + if (r < 5) + delta = 3; + else if (r < 15) + delta = 2; + else if (r < 30) + delta = 1; + else + delta = 0; + if (lrand48() % 2) + delta = -delta; + return temp + delta; +} + +//---------------------------------------------------------------- + +// Function object. Locates a thermostat that is in the same room +// as the device at position pos. + +class ThermostatInSameRoom { +public: + ThermostatInSameRoom( + const StateMap::iterator & pos + ) : m_pos(pos) {} + bool operator()( + pair & p + ) const + { + return( + p.second.type == thermostat + && p.second.location + == m_pos->second.location + ); + } +private: + const StateMap::iterator & m_pos; +}; + +//---------------------------------------------------------------- + +// actual_temp() is a helper function to determine the actual +// temperature returned by a particular thermometer or thermostat. +// The pos argument indicates the device. +// +// The function locates all thermostats that are in the same room +// as the device denoted by pos and computes the average of all +// the thermostats' nominal temperatures. (If no thermostats are +// in the same room as the device, the function assumes that the +// average of the nominal temperatures is DFLT_TEMP.) +// +// The returned temperature varies from the average as +// determined by vary_temp(). + +static +short +actual_temp(const StateMap::iterator & pos) +{ + long sum = 0; + long count = 0; + StateMap::iterator where = find_if( + dstate.begin(), dstate.end(), + ThermostatInSameRoom(pos) + ); + while (where != dstate.end()) { + count++; + sum += where->second.nominal_temp; + where = find_if( + ++where, dstate.end(), + ThermostatInSameRoom(pos) + ); + } + return vary_temp(count == 0 ? DFLT_TEMP : sum / count); +} + +//---------------------------------------------------------------- + +// ICP_get() returns an attribute value of the device with the +// given id. The attribute is named by the attr parameter. The +// value is copied into the buffer pointed to by the value +// pointer. The len parameter is the size of the passed buffer, +// so ICP_get can avoid overrunning the buffer. +// +// By default, thermometers report a temperature that varies +// somewhat around DFLT_TEMP. However, if there is another +// thermostat in the same room as the thermometer, the +// thermometer reports a temperature that varies around that +// thermostat's temperature. For several thermostats that are in +// the same room, the thermometer reports a temperature that +// varies around the average nominal temperature of all the +// thermostats. +// +// Attempts to read from a non-existent device or to read a +// non-existent attribute return -1. A return value of zero +// indicates success. If the supplied buffer is too short to hold +// a value, ICP_get() silently truncates the value and +// returns success. + +extern "C" +int +ICP_get( + unsigned long id, + const char * attr, + void * value, + size_t len) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + + // Depending on the attribute, return the + // corresponding piece of state. + if (strcmp(attr, "model") == 0) { + strncpy((char *)value, pos->second.model, len); + } else if (strcmp(attr, "location") == 0) { + strncpy((char *)value, pos->second.location.c_str(), len); + } else if (strcmp(attr, "nominal_temp") == 0) { + if (pos->second.type != thermostat) + return -1; // Must be thermostat + memcpy( + value, &pos->second.nominal_temp, + min(len, sizeof(pos->second.nominal_temp)) + ); + } else if (strcmp(attr, "temperature") == 0) { + short temp = actual_temp(pos); + memcpy(value, &temp, min(len, sizeof(temp))); + } else if (strcmp(attr, "MIN_TEMP") == 0) { + memcpy(value, &MIN_TEMP, min(len, sizeof(MIN_TEMP))); + } else if (strcmp(attr, "MAX_TEMP") == 0) { + memcpy(value, &MAX_TEMP, min(len, sizeof(MAX_TEMP))); + } else { + return -1; // No such attribute + } + return 0; // OK +} + +//---------------------------------------------------------------- + +// ICP_set() sets the attribute specified by attr to the +// value specified by value for the device with ID id. Attempts to +// write a string longer than MAXSTR bytes (including the +// terminating NUL) result in silent truncation of the string. +// Attempts to access a non-existent device or attribute +// return -1. Attempts to set a nominal temperature outside the +// legal range also return -1. A zero return value +// indicates success. + +extern "C" +int +ICP_set(unsigned long id, const char * attr, const void * value) +{ + // Look for id in state map + StateMap::iterator pos = dstate.find(id); + if (pos == dstate.end()) + return -1; // No such device + + // Change either location or nominal temp, depending on attr. + if (strcmp(attr, "location") == 0) { + pos->second.location.assign( + (const char *)value, MAXSTR - 1 + ); + } else if (strcmp(attr, "nominal_temp") == 0) { + if (pos->second.type != thermostat) + return -1; // Must be thermostat + short temp; + memcpy(&temp, value, sizeof(temp)); + if (temp < MIN_TEMP || temp > MAX_TEMP) + return -1; + pos->second.nominal_temp = temp; + } else { + return -1; // No such attribute + } + return 0; // OK +} diff --git a/TAO/examples/Advanced/ch_8_and_10/icp.h b/TAO/examples/Advanced/ch_8_and_10/icp.h new file mode 100644 index 00000000000..334a6416a77 --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/icp.h @@ -0,0 +1,41 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_8_and_10 +// +// = FILENAME +// icp.h +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + +#ifndef _ICP_H +#define _ICP_H + +extern "C" { + int ICP_online(unsigned long id); // Add device + int ICP_offline(unsigned long id); // Remove device + int ICP_get( // Get attribute + unsigned long id, + const char * attr, + void * value, + size_t len + ); + int ICP_set( // Set attribute + unsigned long id, + const char * attr, + const void * value + ); +} + +#endif /* _ICP_H */ diff --git a/TAO/examples/Advanced/ch_8_and_10/run_test.pl b/TAO/examples/Advanced/ch_8_and_10/run_test.pl new file mode 100755 index 00000000000..74c52a910be --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/run_test.pl @@ -0,0 +1,54 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "../../../../bin"; + +require ACEutils; +require Process; + +$status = 0; +$iorfile = "chapter_test.ior"; +unlink $iorfile; + + + +# Hacked call +$server = Process::Create ("exec ".$EXEPREFIX."server".$EXE_EXT.">$iorfile", + ""); +# Proper call +#$server = Process::Create ($EXEPREFIX."server".$EXE_EXT, ">$iorfile"); + +if (ACE::waitforfile_timed ($iorfile, 15) == -1) { + print STDERR "ERROR: timedout waiting for file <$iorfile>\n"; + $server->Kill (); $server->TimedWait (1); + exit 1; +} + +open(ior_handle, "$iorfile"); +$ior_content = ; + +$client = Process::Create($EXEPREFIX."client$EXE_EXT", "$ior_content"); + +if ($client->TimedWait (60) == -1) { + print STDERR "ERROR: client timedout\n"; + $status = 1; + $client->Kill (); $client->TimedWait (1); +} + + + + +$server->Terminate (); +if ($server->TimedWait (5) == -1) { + print STDERR "ERROR: cannot terminate the server\n"; + $server->Kill (); $server->TimedWait (1); + $status = 1; +} + +unlink $iorfile; + +exit $status; diff --git a/TAO/examples/Advanced/ch_8_and_10/server.cpp b/TAO/examples/Advanced/ch_8_and_10/server.cpp new file mode 100644 index 00000000000..8e600dc794a --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/server.cpp @@ -0,0 +1,464 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_8_and_10 +// +// = FILENAME +// server.cpp +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + +#include "server.h" +#include +#include "icp.h" +//#include +//#include +//---------------------------------------------------------------- + + +// Generic ostream inserter for exceptions. Inserts the exception +// name, if available, and the repository ID otherwise. + +// #if 0 This inserter may or may not be needed for your ORB. + +static ostream & +operator<<(ostream & os, const CORBA::Exception & e) +{ + CORBA::Any tmp; + tmp <<= e; + CORBA::TypeCode_var tc = tmp.type(); + const char * p = tc->name(); + if (*p != '\0') + os << p; + else + os << tc->id(); + return os; +} + +// #endif + +//---------------------------------------------------------------- + +Controller_impl * Thermometer_impl::m_ctrl; // static member + +// Helper function to read the model string from a device. + +CCS::ModelType +Thermometer_impl:: +get_model() +{ + char buf[32]; + assert(ICP_get(m_anum, "model", buf, sizeof(buf)) == 0); + return CORBA::string_dup(buf); +} + +// Helper function to read the temperature from a device. + +CCS::TempType +Thermometer_impl:: +get_temp() +{ + short temp; + assert( + ICP_get(m_anum, "temperature", &temp, sizeof(temp) + ) == 0); + return temp; +} + +// Helper function to read the location from a device. + +CCS::LocType +Thermometer_impl:: +get_loc() +{ + char buf[32]; + assert(ICP_get(m_anum, "location", buf, sizeof(buf)) == 0); + return CORBA::string_dup(buf); +} + +// Helper function to set the location of a device. + +void +Thermometer_impl:: +set_loc(const char * loc) +{ + assert(ICP_set(m_anum, "location", loc) == 0); +} + +// Constructor. + +Thermometer_impl:: +Thermometer_impl( + CCS::AssetType anum, + const char * location +) : m_anum(anum) +{ + assert(ICP_online(anum) == 0); // Mark device as on-line + set_loc(location); + m_ctrl->add_impl(anum, this); // Add self to controller's map +} + +// Destructor. + +Thermometer_impl:: +~Thermometer_impl() +{ + try { + m_ctrl->remove_impl(m_anum); // Remove self from map + ICP_offline(m_anum); // Mark device as off-line + } + catch (...) { + assert(0); // Prevent exceptions from escaping + } +} + +// IDL model attribute. + +CCS::ModelType +Thermometer_impl:: +model() throw(CORBA::SystemException) +{ + return get_model(); +} + +// IDL asset_num attribute. + +CCS::AssetType +Thermometer_impl:: +asset_num() throw(CORBA::SystemException) +{ + return m_anum; +} + +// IDL temperature attribute. + +CCS::TempType +Thermometer_impl:: +temperature() throw(CORBA::SystemException) +{ + return get_temp(); +} + +// IDL location attribute accessor. + +CCS::LocType +Thermometer_impl:: +location() throw(CORBA::SystemException) +{ + return get_loc(); +} + +// IDL location attribute modifier. + +void +Thermometer_impl:: +location(const char * loc) throw(CORBA::SystemException) +{ + set_loc(loc); +} + +//---------------------------------------------------------------- + +// Helper function to get a thermostat's nominal temperature. + +CCS::TempType +Thermostat_impl:: +get_nominal_temp() +{ + short temp; + assert( + ICP_get(m_anum, "nominal_temp", &temp, sizeof(temp) + ) == 0); + return temp; +} + +// Helper function to set a thermostat's nominal temperature. + +CCS::TempType +Thermostat_impl:: +set_nominal_temp(CCS::TempType new_temp) +throw(CCS::Thermostat::BadTemp) +{ + short old_temp; + + // We need to return the previous nominal temperature, + // so we first read the current nominal temperature before + // changing it. + assert(ICP_get( + m_anum, "nominal_temp", + &old_temp, sizeof(old_temp) + ) == 0 + ); + + // Now set the nominal temperature to the new value. + if (ICP_set(m_anum, "nominal_temp", &new_temp) != 0) { + + // If ICP_set() failed, read this thermostat's minimum + // and maximum so we can initialize the BadTemp exception. + CCS::Thermostat::BtData btd; + ICP_get( + m_anum, "MIN_TEMP", + &btd.min_permitted, sizeof(btd.min_permitted) + ); + ICP_get( + m_anum, "MAX_TEMP", + &btd.max_permitted, sizeof(btd.max_permitted) + ); + btd.requested = new_temp; + btd.error_msg = CORBA::string_dup( + new_temp > btd.max_permitted ? "Too hot" : "Too cold" + ); + throw CCS::Thermostat::BadTemp(btd); + } + return old_temp; +} + +// Constructor. + +Thermostat_impl:: +Thermostat_impl( + CCS::AssetType anum, + const char * location, + CCS::TempType nominal_temp +) : Thermometer_impl(anum, location) +{ + // Base Thermometer_impl constructor does most of the + // work, so we need only set the nominal temperature here. + set_nominal_temp(nominal_temp); +} + +// IDL get_nominal operation. + +CCS::TempType +Thermostat_impl:: +get_nominal() throw(CORBA::SystemException) +{ + return get_nominal_temp(); +} + +// IDL set_nominal operation. + +CCS::TempType +Thermostat_impl:: +set_nominal(CCS::TempType new_temp) +throw(CORBA::SystemException, CCS::Thermostat::BadTemp) +{ + return set_nominal_temp(new_temp); +} + +//---------------------------------------------------------------- + +// Helper function for thermometers and thermostats to +// add themselves to the m_assets map. + +void +Controller_impl:: +add_impl(CCS::AssetType anum, Thermometer_impl * tip) +{ + m_assets[anum] = tip; +} + +// Helper function for thermometers and thermostats to +// remove themselves from the m_assets map. + +void +Controller_impl:: +remove_impl(CCS::AssetType anum) +{ + m_assets.erase(anum); +} + +// IDL list operation. + +CCS::Controller::ThermometerSeq * +Controller_impl:: +list() throw(CORBA::SystemException) +{ + // Create a new thermometer sequence. Because we know + // the number of elements we will put onto the sequence, + // we use the maximum constructor. + CCS::Controller::ThermometerSeq_var listv + = new CCS::Controller::ThermometerSeq(m_assets.size()); + listv->length(m_assets.size()); + + // Loop over the m_assets map and create a + // reference for each device. + CORBA::ULong count = 0; + AssetMap::iterator i; + for (i = m_assets.begin(); i != m_assets.end(); i++) + listv[count++] = i->second->_this(); + return listv._retn(); +} + +// IDL change operation. + +void +Controller_impl:: +change( + const CCS::Controller::ThermostatSeq & tlist, + CORBA::Short delta +) throw(CORBA::SystemException, CCS::Controller::EChange) +{ + CCS::Controller::EChange ec; // Just in case we need it + + // We cannot add a delta value to a thermostat's temperature + // directly, so for each thermostat, we read the nominal + // temperature, add the delta value to it, and write + // it back again. + for (CORBA::ULong i = 0; i < tlist.length(); i++) { + if (CORBA::is_nil(tlist[i])) + continue; // Skip nil references + + // Read nominal temp and update it. + CCS::TempType tnom = tlist[i]->get_nominal(); + tnom += delta; + try { + tlist[i]->set_nominal(tnom); + } + catch (const CCS::Thermostat::BadTemp & bt) { + // If the update failed because the temperature + // is out of range, we add the thermostat's info + // to the errors sequence. + CORBA::ULong len = ec.errors.length(); + ec.errors.length(len + 1); + ec.errors[len].tmstat_ref = tlist[i]; + ec.errors[len].info = bt.details; + } + } + + // If we encountered errors in the above loop, + // we will have added elements to the errors sequence. + if (ec.errors.length() != 0) + throw ec; +} + +// IDL find operation + +void +Controller_impl:: +find(CCS::Controller::SearchSeq & slist) +throw(CORBA::SystemException) +{ + // Loop over input list and look up each device. + CORBA::ULong listlen = slist.length(); + for (CORBA::ULong i = 0; i < listlen; i++) { + + AssetMap::iterator where; // Iterator for asset map + int num_found = 0; // Num matched per iteration + + // Assume we will not find a matching device. + slist[i].device = CCS::Thermometer::_nil(); + + // Work out whether we are searching by asset, + // model, or location. + CCS::Controller::SearchCriterion sc = slist[i].key._d(); + if (sc == CCS::Controller::ASSET) { + // Search for matching asset number. + where = m_assets.find(slist[i].key.asset_num()); + if (where != m_assets.end()) + slist[i].device = where->second->_this(); + } else { + // Search for model or location string. + const char * search_str; + if (sc == CCS::Controller::LOCATION) + search_str = slist[i].key.loc(); + else + search_str = slist[i].key.model_desc(); + + // Find first matching device (if any). + where = find_if( + m_assets.begin(), m_assets.end(), + StrFinder(sc, search_str) + ); + + // While there are matches... + while (where != m_assets.end()) { + if (num_found == 0) { + // First match overwrites reference + // in search record. + slist[i].device = where->second->_this(); + } else { + // Each further match appends a new + // element to the search sequence. + CORBA::ULong len = slist.length(); + slist.length(len + 1); + slist[len].key = slist[i].key; + slist[len].device = where->second->_this(); + } + num_found++; + + // Find next matching device with this key. + where = find_if( + ++where, m_assets.end(), + StrFinder(sc, search_str) + ); + } + } + } + cerr << "end" << endl; +} + +//---------------------------------------------------------------- + +int +main(int argc, char * argv[]) +{ + try { + // Initialize orb + CORBA::ORB_var orb = CORBA::ORB_init(argc, argv); + + // Get reference to Root POA. + CORBA::Object_var obj + = orb->resolve_initial_references("RootPOA"); + PortableServer::POA_var poa + = PortableServer::POA::_narrow(obj.in()); + + // Activate POA manager + PortableServer::POAManager_var mgr + = poa->the_POAManager(); + mgr->activate(); + + // Create a controller and set static m_ctrl member + // for thermostats and thermometers. + Controller_impl ctrl_servant; + Thermometer_impl::m_ctrl = &ctrl_servant; + + // Write controller stringified reference to stdout + CCS::Controller_var ctrl = ctrl_servant._this(); + CORBA::String_var str = orb->object_to_string(ctrl.in()); + cout << str.in() << endl << endl; + + // Create a few devices. (Thermometers have odd asset + // numbers, thermostats have even asset numbers.) + Thermometer_impl thermo1(2029, "Deep Thought"); + Thermometer_impl thermo2(8053, "HAL"); + Thermometer_impl thermo3(1027, "ENIAC"); + + Thermostat_impl tmstat1(3032, "Colossus", 68); + Thermostat_impl tmstat2(4026, "ENIAC", 60); + Thermostat_impl tmstat3(4088, "ENIAC", 50); + Thermostat_impl tmstat4(8042, "HAL", 40); + + // Accept requests + orb->run(); + } + catch (const CORBA::Exception & e) { + cerr << "Uncaught CORBA exception: " << e << endl; + return 1; + } + catch (...) { + assert(0); // Unexpected exception, dump core + } + return 0; +} diff --git a/TAO/examples/Advanced/ch_8_and_10/server.h b/TAO/examples/Advanced/ch_8_and_10/server.h new file mode 100644 index 00000000000..b94cb6e5d92 --- /dev/null +++ b/TAO/examples/Advanced/ch_8_and_10/server.h @@ -0,0 +1,167 @@ +// $Id$ +// ============================================================================ +// +// = LIBRARY +// TAO/examples/Advanced/ch_8_and_10 +// +// = FILENAME +// server.h +// +// = AUTHORS +// Source code used in TAO has been modified and adapted from the code +// provided in the book, "Advanced CORBA Programming with C++" by Michi +// Henning and Steve Vinoski. Copyright 1999. Addison-Wesley, Reading, +// MA. +// +// Modified for TAO by Mike Moran +// +// ============================================================================ + + + + +#ifndef server_HH_ +#define server_HH_ + +#include "CCSS.h" +#include +//#include + + +class Controller_impl; + +class Thermometer_impl : public virtual POA_CCS::Thermometer { +public: + // CORBA attributes + virtual CCS::ModelType model() + throw(CORBA::SystemException); + virtual CCS::AssetType asset_num() + throw(CORBA::SystemException); + virtual CCS::TempType temperature() + throw(CORBA::SystemException); + virtual CCS::LocType location() + throw(CORBA::SystemException); + virtual void location(const char * loc) + throw(CORBA::SystemException); + + // Constructor and destructor + Thermometer_impl(CCS::AssetType anum, const char * location); + virtual ~Thermometer_impl(); + + static Controller_impl * m_ctrl; // My controller + +protected: + const CCS::AssetType m_anum; // My asset number + +private: + // Helper functions + CCS::ModelType get_model(); + CCS::TempType get_temp(); + CCS::LocType get_loc(); + void set_loc(const char * new_loc); + + // Copy and assignment not supported + Thermometer_impl(const Thermometer_impl &); + void operator=(const Thermometer_impl &); +}; + +class Thermostat_impl : + public virtual POA_CCS::Thermostat, + public virtual Thermometer_impl { +public: + // CORBA operations + virtual CCS::TempType get_nominal() + throw(CORBA::SystemException); + virtual CCS::TempType set_nominal( + CCS::TempType new_temp + ) throw( + CORBA::SystemException, + CCS::Thermostat::BadTemp + ); + + // Constructor and destructor + Thermostat_impl( + CCS::AssetType anum, + const char * location, + CCS::TempType nominal_temp + ); + virtual ~Thermostat_impl() {} + +private: + // Helper functions + CCS::TempType get_nominal_temp(); + CCS::TempType set_nominal_temp(CCS::TempType new_temp) + throw(CCS::Thermostat::BadTemp); + + // Copy and assignment not supported + Thermostat_impl(const Thermostat_impl &); + void operator=(const Thermostat_impl &); +}; + +class Controller_impl : public virtual POA_CCS::Controller { +public: + // CORBA operations + virtual CCS::Controller::ThermometerSeq * + list() throw(CORBA::SystemException); + virtual void + find(CCS::Controller::SearchSeq & slist) + throw(CORBA::SystemException); + virtual void + change( + const CCS::Controller::ThermostatSeq & tlist, + CORBA::Short delta + ) throw( + CORBA::SystemException, + CCS::Controller::EChange + ); + + // Constructor and destructor + Controller_impl() {} + virtual ~Controller_impl() {} + + // Helper functions to allow thermometers and + // thermostats to add themselves to the m_assets map + // and to remove themselves again. + void add_impl(CCS::AssetType anum, Thermometer_impl * tip); + void remove_impl(CCS::AssetType anum); + +private: + // Map of known servants + typedef map AssetMap; + AssetMap m_assets; + + // Copy and assignment not supported + Controller_impl(const Controller_impl &); + void operator=(const Controller_impl &); + + // Function object for the find_if algorithm to search for + // devices by location and model string. + class StrFinder { + public: + StrFinder( + CCS::Controller::SearchCriterion sc, + const char * str + ) : m_sc(sc), m_str(str) {} + bool operator()( + pair & p + ) const + { + switch (m_sc) { + case CCS::Controller::LOCATION: + return strcmp(p.second->location(), m_str) == 0; + break; + case CCS::Controller::MODEL: + return strcmp(p.second->model(), m_str) == 0; + break; + default: + assert(0); // Precondition violation + } + return 0; // Stops compiler warning + } + private: + CCS::Controller::SearchCriterion m_sc; + const char * m_str; + }; +}; + +#endif diff --git a/TAO/examples/Advanced/run_test.pl b/TAO/examples/Advanced/run_test.pl new file mode 100755 index 00000000000..cab8085049f --- /dev/null +++ b/TAO/examples/Advanced/run_test.pl @@ -0,0 +1,62 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "../../../bin"; +require ACEutils; +require Process; + +$status = 0; + + +sub run_test_from_current_directory{ + announce_test(); + $test = Process::Create($EXEPREFIX."run_test.pl",""); + wait_for_test_to_finish(); +} + +sub announce_test{ + use Cwd; + $dir = cwd(); + print STDOUT "__________________________________________________________ \n"; + print STDOUT "**running test in $dir : \n"; +} + +sub wait_for_test_to_finish { + if ($test->TimedWait (60) == -1) { + print STDERR "ERROR: run_test.pl timedout\n"; + $status = 1; + $test->Kill (); $test->TimedWait (1); + } +} + + + + +# change to each example's directory, and run their test +chdir "ch_3" or die "can't cd to ch_3 $!\n"; +run_test_from_current_directory(); + +chdir "../ch_8_and_10" or die "can't cd to ch_8_and_10 $!\n"; +run_test_from_current_directory(); + +chdir "../ch_12" or die "can't cd to ch_12 $!\n"; +run_test_from_current_directory(); + +chdir "../ch_18" or die "can't cd to ch_18 $!\n"; +run_test_from_current_directory(); + +#chdir "../ch_19" or die "can't cd to ch_19 $!\n"; +#run_test_from_current_directory(); + +#chdir "../ch_21" or die "can't cd to ch_21 $!\n"; +#run_test_from_current_directory(); + +exit $status; + + + + -- cgit v1.2.1