Since last public TDAQ release there are important public API changes, which can require modifications of the user's code!
The interfaces of configuration packages were implemented long time ago, when used compilers did not supported exceptions. By that reason most of the methods of configuration classes returned boolean status to indicate that a method was successful or had a problem.
During summer 2006 the DAQ/HLT-I coordination group took a decision the ERS has to be used by all packages of TDAQ release to report problems starting from TDAQ release 01-07-00. Now the status reporting mechanism of methods of config classes has been changed: to report a problem they throw ERS exception and the return type of them is changed to void.
Each method of config classes and classes of data access libraries generated by genconfig has explicit exception specification. For complete information about particular method see generated Doxygen documentation or appropriate header files. The following config exceptions can be thrown:
All above exceptions have common class daq::config::Exception, which in turn is derived from the ers::Issue. The catch of daq::config::Exception is recommending to be used, if exact reason of error is not important for the user's code.
If the method's exception specification is throw(), then such method does not throw any exception.
Below there are several examples of changes.
In the past to check status of the database loading it was necessary to use special method loaded() as shown below:
std::string data("oksconfig:db.data.xml"); Configuration db(data); if(!db.loaded()) { std::cerr << "ERROR: cannot load database " << data << std::endl; return; } ... // code working with database
Now the call of the method loaded() is not needed any more. One can catch exception in a common try / catch block as shown below:
try { Configuration db("oksconfig:db.data.xml"); ... // code working with database } catch (daq::config::Exception & ex) { std::cerr << "Caught exception " << ex << std::endl; return; }
There are two ways to get an object by id: using config layer defined by this package and using generated data access library layer (see genconfig and e.g. dal packages).
The correct old code to get an object using the config layer was:
// return true if object has been printed bool print_obj(::Configuration& db, const std::string& class_name, const std::string& object_id) { ConfigObject obj; // try to get object // in case of an error, the plug-in reports the problem to standard error stream if(db.get(class_name, object_id, obj) == false) { std::cerr << "ERROR: cannot get object " << object_id << " of class " << class_name << std::endl; return false; } std::cout << obj; return true; }
Now it has to be replaced by:
// return true if object has been printed bool print_obj(::Configuration& db, const std::string& class_name, const std::string& object_id) throw() { try { ConfigObject obj; db.get(class_name, object_id, obj); std::cout << obj; return true; } catch (daq::config::NotFound& ex) { std::cerr << "ERROR: cannot get object " << object_id << " of class " << class_name << std::endl; } catch (daq::config::Generic& ex) { // catch and report plug-in errors std::cerr << "Caught exception " << ex << std::endl; } return false; }
In case when generated DAL layer is used to get a template object by ID, the daq::config::NotFound exception is not thrown, but it is necessary to catch generic daq::config::Exception as shown below:
// return true if object has been printed bool print_application(::Configuration& db, const std::string& object_id) throw() { try { const daq::core::BaseApplication * a = db.get<daq::core::BaseApplication>(object_id); if(a) { std::cout << *a << std::endl; return true; } else { std::cerr << "ERROR: there is no application object with id " << object_id << std::endl; } } catch (daq::config::Exception& ex) { // catch and report plug-in errors, also can use here daq::config::Generic std::cerr << "Caught exception " << ex << std::endl; } return false; }
In a similar way to above, the config layer can throw daq:config::NotFound exception, if there is no class with given name, see:
const char * class_name = "Segment"; try { Configuration db("rdbconfig:RDB"); std::vector<ConfigObject> objects; db.get(class_name, objects); // get all objects of class "Segment" std::cout << "There are " << objects.size() << " objects of " << class_name << " class\n"; } catch(daq::config::NotFound& ex) { std::cerr << "Wrong database schema, caught " << ex << ". Check the right database is used!\n"; } catch(daq::config::Exception& ex) { std::cerr << "Caught exception " << ex << std::endl; }
For corresponding generated data access library template method get() the daq::config::NotFound exception is not thrown. In case if a database with wrong schema is loaded, the problem is reported by daq::config::Generic exception:
try { Configuration db("rdbconfig:RDB"); std::vector<const daq::core::Segment*> objs; db.get(objs); // get all objects of class "Segment" std::cout << "There are " << objects.size() << " objects of Segment class\n"; } catch(daq::config::Exception& ex) { std::cerr << "Caught exception " << ex << std::endl; }
In the past it was necessary to check boolean status of generated DAL set method and get/set status of config layer methods dealing with attributes and relationships. Now all such methods are void and throw generic daq::config::Exception in case of problems, e.g.:
::ConfigObject obj = ...; std::string name; if(obj.get("Name", name) == false) { std::cerr << "ERROR: cannot read Name attribute" << std::endl; } ConfigObject item; if(obj.get("Item", item) == false) { std::cerr << "ERROR: cannot read Item relationship" << std::endl; } daq::core::Application * a = ...; name = a->get_Name(); const daq::core::Item * i = a->get_Item();
Now such code needs to be changed to the following:
try { ::ConfigObject obj = ...; std::string name; obj.get("Name", name); ConfigObject item; obj.get("Item", item); daq::core::Application * a = ...; name = a->get_Name(); const daq::core::Item * i = a->get_Item(); } catch (daq::config::Exception& ex) { std::cerr << "Caught exception " << ex << std::endl; }
When receive a notification, update objects of derived classes stored in the clients configuration cache (this problem has been found in the Run Control). Note, the update of direct and base classes in case of notification was implemented before.
Below there are several examples explaining different mechanisms of objects updates in client's cache depending on subscription:
Thus, subscription on:
Add method Configuration::unread_objects() to unread unread objects of template classes in the client's configuration cache. This is required after reading parameters for substitution, since cache contains objects with non-substituted attributes.
Also note config changes in the LST release.