otsdaq  v2_03_00
ConfigurationManagerRW.cc
1 #include "otsdaq-core/ConfigurationInterface/ConfigurationManagerRW.h"
2 
3 // backbone includes
4 //#include "otsdaq-core/TablePluginDataFormats/ConfigurationAliases.h"
5 //#include "otsdaq-core/TablePluginDataFormats/Configurations.h"
6 //#include "otsdaq-core/TablePluginDataFormats/DefaultConfigurations.h"
7 //#include "otsdaq-core/TablePluginDataFormats/VersionAliases.h"
8 
9 //#include "otsdaq-core/ConfigurationInterface/ConfigurationInterface.h"//All configurable
10 // objects are included here
11 
12 //
13 //#include "otsdaq-core/TablePluginDataFormats/DetectorTable.h"
14 //#include "otsdaq-core/TablePluginDataFormats/MaskTable.h"
15 //#include "otsdaq-core/TablePluginDataFormats/DetectorToFETable.h"
16 //
17 
18 //#include "otsdaq-core/ConfigurationInterface/DACStream.h"
19 //#include "otsdaq-core/ConfigurationDataFormats/TableGroupKey.h"
20 //
21 //#include "otsdaq-core/ConfigurationInterface/FileConfigurationInterface.h"
22 //
23 //#include <cassert>
24 
25 #include <dirent.h>
26 
27 using namespace ots;
28 
29 #undef __MF_SUBJECT__
30 #define __MF_SUBJECT__ "ConfigurationManagerRW"
31 
32 #define TABLE_INFO_PATH std::string(getenv("TABLE_INFO_PATH")) + "/"
33 #define TABLE_INFO_EXT "Info.xml"
34 
35 #define CORE_TABLE_INFO_FILENAME \
36  ((getenv("SERVICE_DATA_PATH") == NULL) \
37  ? (std::string(getenv("USER_DATA")) + "/ServiceData") \
38  : (std::string(getenv("SERVICE_DATA_PATH")))) + \
39  "/CoreTableInfoNames.dat"
40 
41 //==============================================================================
42 // ConfigurationManagerRW
43 ConfigurationManagerRW::ConfigurationManagerRW(std::string username)
44  : ConfigurationManager(username) // for use as author of new views
45 {
46  __COUT__ << "Using Config Mgr with Write Access! (for " << username << ")" << __E__;
47 
48  // FIXME only necessarily temporarily while Lore is still using fileSystem xml
49  theInterface_ =
50  ConfigurationInterface::getInstance(false); // false to use artdaq DB
51  // FIXME -- can delete this change of
52  // interface once RW and regular use
53  // same interface instance
54 
55  //=========================
56  // dump names of core tables (so UpdateOTS.sh can copy core tables for user)
57  // only if table does not exist
58  {
59  const std::set<std::string>& contextMemberNames = getContextMemberNames();
60  const std::set<std::string>& backboneMemberNames = getBackboneMemberNames();
61  const std::set<std::string>& iterateMemberNames = getIterateMemberNames();
62 
63  FILE* fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "r");
64 
65  __COUT__ << "Updating core tables table..." << __E__;
66 
67  if(fp) // check for all core table names in file, and force their presence
68  {
69  std::vector<unsigned int> foundVector;
70  char line[100];
71  for(const auto& name : contextMemberNames)
72  {
73  foundVector.push_back(false);
74  rewind(fp);
75  while(fgets(line, 100, fp))
76  {
77  if(strlen(line) < 1)
78  continue;
79  line[strlen(line) - 1] = '\0'; // remove endline
80  if(strcmp(line, ("ContextGroup/" + name).c_str()) == 0) // is match?
81  {
82  foundVector.back() = true;
83  //__COUTV__(name);
84  break;
85  }
86  }
87  }
88 
89  for(const auto& name : backboneMemberNames)
90  {
91  foundVector.push_back(false);
92  rewind(fp);
93  while(fgets(line, 100, fp))
94  {
95  if(strlen(line) < 1)
96  continue;
97  line[strlen(line) - 1] = '\0'; // remove endline
98  if(strcmp(line, ("BackboneGroup/" + name).c_str()) == 0) // is match?
99  {
100  foundVector.back() = true;
101  //__COUTV__(name);
102  break;
103  }
104  }
105  }
106 
107  for(const auto& name : iterateMemberNames)
108  {
109  foundVector.push_back(false);
110  rewind(fp);
111  while(fgets(line, 100, fp))
112  {
113  if(strlen(line) < 1)
114  continue;
115  line[strlen(line) - 1] = '\0'; // remove endline
116  if(strcmp(line, ("IterateGroup/" + name).c_str()) == 0) // is match?
117  {
118  foundVector.back() = true;
119  //__COUTV__(name);
120  break;
121  }
122  }
123  }
124 
125  fclose(fp);
126 
127  // for(const auto &found:foundVector)
128  // __COUTV__(found);
129 
130  // open file for appending the missing names
131  fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "a");
132  if(fp)
133  {
134  unsigned int i = 0;
135  for(const auto& name : contextMemberNames)
136  {
137  if(!foundVector[i])
138  fprintf(fp, "ContextGroup/%s\n", name.c_str());
139 
140  ++i;
141  }
142  for(const auto& name : backboneMemberNames)
143  {
144  if(!foundVector[i])
145  fprintf(fp, "BackboneGroup/%s\n", name.c_str());
146 
147  ++i;
148  }
149  for(const auto& name : iterateMemberNames)
150  {
151  if(!foundVector[i])
152  fprintf(fp, "IterateGroup/%s\n", name.c_str());
153 
154  ++i;
155  }
156  fclose(fp);
157  }
158  else
159  {
160  __SS__ << "Failed to open core table info file for appending: "
161  << CORE_TABLE_INFO_FILENAME << __E__;
162  __SS_THROW__;
163  }
164  }
165  else
166  {
167  fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "w");
168  if(fp)
169  {
170  for(const auto& name : contextMemberNames)
171  fprintf(fp, "ContextGroup/%s\n", name.c_str());
172  for(const auto& name : backboneMemberNames)
173  fprintf(fp, "BackboneGroup/%s\n", name.c_str());
174  for(const auto& name : iterateMemberNames)
175  fprintf(fp, "IterateGroup/%s\n", name.c_str());
176  fclose(fp);
177  }
178  else
179  {
180  __SS__ << "Failed to open core table info file: "
181  << CORE_TABLE_INFO_FILENAME << __E__;
182  __SS_THROW__;
183  }
184  }
185  } // end dump names of core tables
186 } // end constructor
187 
188 //==============================================================================
189 // getAllTableInfo()
190 // Used by ConfigurationGUISupervisor to get all the info for the existing configurations
191 //
192 // if(accumulatedErrors)
193 // this implies allowing column errors and accumulating such errors in given string
194 const std::map<std::string, TableInfo>& ConfigurationManagerRW::getAllTableInfo(
195  bool refresh, std::string* accumulatedErrors, const std::string& errorFilterName)
196 {
197  // allTableInfo_ is container to be returned
198 
199  if(accumulatedErrors)
200  *accumulatedErrors = "";
201 
202  if(!refresh)
203  return allTableInfo_;
204 
205  // else refresh!
206  allTableInfo_.clear();
207  allGroupInfo_.clear();
208 
209  TableBase* table;
210 
211  // existing configurations are defined by which infos are in TABLE_INFO_PATH
212  // can test that the class exists based on this
213  // and then which versions
214  __COUT__ << "======================================================== "
215  "getAllTableInfo start"
216  << __E__;
217  __COUT__ << "Refreshing all! Extracting list of tables..." << __E__;
218  DIR* pDIR;
219  struct dirent* entry;
220  std::string path = TABLE_INFO_PATH;
221  char fileExt[] = TABLE_INFO_EXT;
222  const unsigned char MIN_TABLE_NAME_SZ = 3;
223  if((pDIR = opendir(path.c_str())) != 0)
224  {
225  while((entry = readdir(pDIR)) != 0)
226  {
227  // enforce table name length
228  if(strlen(entry->d_name) < strlen(fileExt) + MIN_TABLE_NAME_SZ)
229  continue;
230 
231  // find file names with correct file extenstion
232  if(strcmp(&(entry->d_name[strlen(entry->d_name) - strlen(fileExt)]),
233  fileExt) != 0)
234  continue; // skip different extentions
235 
236  entry->d_name[strlen(entry->d_name) - strlen(fileExt)] =
237  '\0'; // remove file extension to get table name
238 
239  //__COUT__ << entry->d_name << __E__;
240 
241  // 0 will force the creation of new instance (and reload from Info)
242  table = 0;
243 
244  try // only add valid table instances to maps
245  {
246  theInterface_->get(table, entry->d_name, 0, 0,
247  true); // dont fill
248  }
249  catch(cet::exception)
250  {
251  if(table)
252  delete table;
253  table = 0;
254 
255  __COUT__ << "Skipping! No valid class found for... " << entry->d_name
256  << "\n";
257  continue;
258  }
259  catch(std::runtime_error& e)
260  {
261  if(table)
262  delete table;
263  table = 0;
264 
265  __COUT__ << "Skipping! No valid class found for... " << entry->d_name
266  << "\n";
267  __COUT__ << "Error: " << e.what() << __E__;
268 
269  // for a runtime_error, it is likely that columns are the problem
270  // the Table Editor needs to still fix these.. so attempt to
271  // proceed.
272  if(accumulatedErrors)
273  {
274  if(errorFilterName == "" || errorFilterName == entry->d_name)
275  {
276  *accumulatedErrors += std::string("\nIn table '") +
277  entry->d_name + "'..." +
278  e.what(); // global accumulate
279 
280  __SS__ << "Attempting to allow illegal columns!" << __E__;
281  *accumulatedErrors += ss.str();
282  }
283 
284  // attempt to recover and build a mock-up
285  __COUT__ << "Attempting to allow illegal columns!" << __E__;
286 
287  std::string returnedAccumulatedErrors;
288  try
289  {
290  // table = new TableBase(entry->d_name,
291  // &returnedAccumulatedErrors);
292  table = new TableBase(entry->d_name, &returnedAccumulatedErrors);
293  }
294  catch(...)
295  {
296  __COUT__
297  << "Skipping! Allowing illegal columns didn't work either... "
298  << entry->d_name << "\n";
299  continue;
300  }
301  __COUT__ << "Error (but allowed): " << returnedAccumulatedErrors
302  << __E__;
303 
304  if(errorFilterName == "" || errorFilterName == entry->d_name)
305  *accumulatedErrors +=
306  std::string("\nIn table '") + entry->d_name + "'..." +
307  returnedAccumulatedErrors; // global accumulate
308  }
309  else
310  continue;
311  }
312 
313  //__COUT__ << "Instance created: " << entry->d_name << "\n"; //found!
314 
315  if(nameToTableMap_[entry->d_name]) // handle if instance existed
316  {
317  // copy the temporary versions! (or else all is lost)
318  std::set<TableVersion> versions =
319  nameToTableMap_[entry->d_name]->getStoredVersions();
320  for(auto& version : versions)
321  if(version.isTemporaryVersion())
322  {
323  //__COUT__ << "copying tmp = " << version << __E__;
324 
325  try // do NOT let TableView::init() throw here
326  {
327  nameToTableMap_[entry->d_name]->setActiveView(version);
328  table->copyView( // this calls TableView::init()
329  nameToTableMap_[entry->d_name]->getView(),
330  version,
331  username_);
332  }
333  catch(...) // do NOT let invalid temporary version throw at this
334  // point
335  {
336  } // just trust configurationBase throws out the failed version
337  }
338  //__COUT__ << "deleting: " << entry->d_name << "\n"; //found!
339  delete nameToTableMap_[entry->d_name];
340  nameToTableMap_[entry->d_name] = 0;
341  }
342 
343  nameToTableMap_[entry->d_name] = table;
344 
345  allTableInfo_[entry->d_name].tablePtr_ = table;
346  allTableInfo_[entry->d_name].versions_ = theInterface_->getVersions(table);
347 
348  // also add any existing temporary versions to all table info
349  // because the interface wont find those versions
350  std::set<TableVersion> versions =
351  nameToTableMap_[entry->d_name]->getStoredVersions();
352  for(auto& version : versions)
353  if(version.isTemporaryVersion())
354  {
355  //__COUT__ << "surviving tmp = " << version << __E__;
356  allTableInfo_[entry->d_name].versions_.emplace(version);
357  }
358  }
359  closedir(pDIR);
360  }
361  __COUT__ << "Extracting list of tables complete" << __E__;
362 
363  // call init to load active versions by default
364  init(accumulatedErrors);
365 
366  __COUT__
367  << "======================================================== getAllTableInfo end"
368  << __E__;
369 
370  // get Group Info too!
371  try
372  {
373  // build allGroupInfo_ for the ConfigurationManagerRW
374 
375  std::set<std::string /*name*/> tableGroups =
376  theInterface_->getAllTableGroupNames();
377  __COUT__ << "Number of Groups: " << tableGroups.size() << __E__;
378 
379  TableGroupKey key;
380  std::string name;
381  for(const auto& fullName : tableGroups)
382  {
383  TableGroupKey::getGroupNameAndKey(fullName, name, key);
384  cacheGroupKey(name, key);
385  }
386 
387  // for each group get member map & comment, author, time, and type for latest key
388  for(auto& groupInfo : allGroupInfo_)
389  {
390  try
391  {
392  loadTableGroup(groupInfo.first /*groupName*/,
393  groupInfo.second.getLatestKey(),
394  false /*doActivate*/,
395  &groupInfo.second.latestKeyMemberMap_ /*groupMembers*/,
396  0 /*progressBar*/,
397  0 /*accumulateErrors*/,
398  &groupInfo.second.latestKeyGroupComment_,
399  &groupInfo.second.latestKeyGroupAuthor_,
400  &groupInfo.second.latestKeyGroupCreationTime_,
401  true /*doNotLoadMember*/,
402  &groupInfo.second.latestKeyGroupTypeString_);
403  }
404  catch(...)
405  {
406  __COUT_WARN__
407  << "Error occurred loading latest group info into cache for '"
408  << groupInfo.first << "'..." << __E__;
409  groupInfo.second.latestKeyGroupComment_ = "UNKNOWN";
410  groupInfo.second.latestKeyGroupAuthor_ = "UNKNOWN";
411  groupInfo.second.latestKeyGroupCreationTime_ = "0";
412  groupInfo.second.latestKeyGroupTypeString_ = "UNKNOWN";
413  }
414  } // end group info loop
415  } // end get group info
416  catch(const std::runtime_error& e)
417  {
418  __SS__ << "A fatal error occurred reading the info for all table groups. Error: "
419  << e.what() << __E__;
420  __COUT_ERR__ << "\n" << ss.str();
421  if(accumulatedErrors)
422  *accumulatedErrors += ss.str();
423  else
424  throw;
425  }
426  catch(...)
427  {
428  __SS__ << "An unknown fatal error occurred reading the info for all table groups."
429  << __E__;
430  __COUT_ERR__ << "\n" << ss.str();
431  if(accumulatedErrors)
432  *accumulatedErrors += ss.str();
433  else
434  throw;
435  }
436 
437  return allTableInfo_;
438 } // end getAllTableInfo
439 
440 //==============================================================================
441 // getVersionAliases()
442 // get version aliases organized by table, for currently active backbone tables
443 // add scratch versions to the alias map returned by ConfigurationManager
444 std::map<std::string /*table name*/,
445  std::map<std::string /*version alias*/, TableVersion /*aliased version*/> >
446 ConfigurationManagerRW::getVersionAliases(void) const
447 {
448  //__COUT__ << "getVersionAliases()" << __E__;
449  std::map<std::string /*table name*/,
450  std::map<std::string /*version alias*/, TableVersion /*aliased version*/> >
451  retMap = ConfigurationManager::getVersionAliases();
452 
453  // always have scratch alias for each table that has a scratch version
454  // overwrite map entry if necessary
455  if(!ConfigurationInterface::isVersionTrackingEnabled())
456  for(const auto& tableInfo : allTableInfo_)
457  for(const auto& version : tableInfo.second.versions_)
458  if(version.isScratchVersion())
459  retMap[tableInfo.first][ConfigurationManager::SCRATCH_VERSION_ALIAS] =
460  TableVersion(TableVersion::SCRATCH);
461 
462  return retMap;
463 } // end getVersionAliases()
464 
465 //==============================================================================
466 // setActiveGlobalConfiguration
467 // load table group and activate
468 // deactivates previous table group of same type if necessary
469 void ConfigurationManagerRW::activateTableGroup(const std::string& configGroupName,
470  TableGroupKey configGroupKey,
471  std::string* accumulatedTreeErrors)
472 {
473  loadTableGroup(configGroupName,
474  configGroupKey,
475  true, // loads and activates
476  0, // no members needed
477  0, // no progress bar
478  accumulatedTreeErrors); // accumulate warnings or not
479 
480  if(accumulatedTreeErrors && *accumulatedTreeErrors != "")
481  {
482  __COUT_ERR__ << "Errors were accumulated so de-activating group: "
483  << configGroupName << " (" << configGroupKey << ")" << __E__;
484  try // just in case any lingering pieces, lets deactivate
485  {
486  destroyTableGroup(configGroupName, true);
487  }
488  catch(...)
489  {
490  }
491  }
492 
493  __COUT_INFO__ << "Updating persistent active groups to "
494  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << " ..." << __E__;
495  __MOUT_INFO__ << "Updating persistent active groups to "
496  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << " ..." << __E__;
497 
498  std::string fn = ConfigurationManager::ACTIVE_GROUPS_FILENAME;
499  FILE* fp = fopen(fn.c_str(), "w");
500  if(!fp)
501  {
502  __SS__ << "Fatal Error! Unable to open the file "
503  << ConfigurationManager::ACTIVE_GROUPS_FILENAME
504  << " for editing! Is there a permissions problem?" << __E__;
505  __COUT_ERR__ << ss.str();
506  __SS_THROW__;
507  return;
508  }
509 
510  __MCOUT_INFO__("Active Context table group: "
511  << theContextTableGroup_ << "("
512  << (theContextTableGroupKey_
513  ? theContextTableGroupKey_->toString().c_str()
514  : "-1")
515  << ")" << __E__);
516  __MCOUT_INFO__("Active Backbone table group: "
517  << theBackboneTableGroup_ << "("
518  << (theBackboneTableGroupKey_
519  ? theBackboneTableGroupKey_->toString().c_str()
520  : "-1")
521  << ")" << __E__);
522  __MCOUT_INFO__("Active Iterate table group: "
523  << theIterateTableGroup_ << "("
524  << (theIterateTableGroupKey_
525  ? theIterateTableGroupKey_->toString().c_str()
526  : "-1")
527  << ")" << __E__);
528  __MCOUT_INFO__("Active Configuration table group: "
529  << theConfigurationTableGroup_ << "("
530  << (theConfigurationTableGroupKey_
531  ? theConfigurationTableGroupKey_->toString().c_str()
532  : "-1")
533  << ")" << __E__);
534 
535  fprintf(fp, "%s\n", theContextTableGroup_.c_str());
536  fprintf(
537  fp,
538  "%s\n",
539  theContextTableGroupKey_ ? theContextTableGroupKey_->toString().c_str() : "-1");
540  fprintf(fp, "%s\n", theBackboneTableGroup_.c_str());
541  fprintf(
542  fp,
543  "%s\n",
544  theBackboneTableGroupKey_ ? theBackboneTableGroupKey_->toString().c_str() : "-1");
545  fprintf(fp, "%s\n", theIterateTableGroup_.c_str());
546  fprintf(
547  fp,
548  "%s\n",
549  theIterateTableGroupKey_ ? theIterateTableGroupKey_->toString().c_str() : "-1");
550  fprintf(fp, "%s\n", theConfigurationTableGroup_.c_str());
551  fprintf(fp,
552  "%s\n",
553  theConfigurationTableGroupKey_
554  ? theConfigurationTableGroupKey_->toString().c_str()
555  : "-1");
556  fclose(fp);
557 }
558 
559 //==============================================================================
560 // createTemporaryBackboneView
561 // sourceViewVersion of INVALID is from MockUp, else from valid view version
562 // returns temporary version number (which is always negative)
563 TableVersion ConfigurationManagerRW::createTemporaryBackboneView(
564  TableVersion sourceViewVersion)
565 {
566  __COUT_INFO__ << "Creating temporary backbone view from version " << sourceViewVersion
567  << __E__;
568 
569  // find common available temporary version among backbone members
570  TableVersion tmpVersion =
571  TableVersion::getNextTemporaryVersion(); // get the default temporary version
572  TableVersion retTmpVersion;
573  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
574  for(auto& name : backboneMemberNames)
575  {
576  retTmpVersion =
577  ConfigurationManager::getTableByName(name)->getNextTemporaryVersion();
578  if(retTmpVersion < tmpVersion)
579  tmpVersion = retTmpVersion;
580  }
581 
582  __COUT__ << "Common temporary backbone version found as " << tmpVersion << __E__;
583 
584  // create temporary views from source version to destination temporary version
585  for(auto& name : backboneMemberNames)
586  {
587  retTmpVersion =
588  getTableByName(name)->createTemporaryView(sourceViewVersion, tmpVersion);
589  if(retTmpVersion != tmpVersion)
590  {
591  __SS__ << "Failure! Temporary view requested was " << tmpVersion
592  << ". Mismatched temporary view created: " << retTmpVersion << __E__;
593  __COUT_ERR__ << ss.str();
594  __SS_THROW__;
595  }
596  }
597 
598  return tmpVersion;
599 }
600 
601 //==============================================================================
602 TableBase* ConfigurationManagerRW::getTableByName(const std::string& tableName)
603 {
604  if(nameToTableMap_.find(tableName) == nameToTableMap_.end())
605  {
606  __SS__ << "Table not found with name: " << tableName << __E__;
607  size_t f;
608  if((f = tableName.find(' ')) != std::string::npos)
609  ss << "There was a space character found in the table name needle at "
610  "position "
611  << f << " in the string (was this intended?). " << __E__;
612  __COUT_ERR__ << "\n" << ss.str();
613  __SS_THROW__;
614  }
615  return nameToTableMap_[tableName];
616 }
617 
618 //==============================================================================
619 // getVersionedTableByName
620 // Used by table GUI to load a particular table-version pair as the active version.
621 // This table instance must already exist and be owned by ConfigurationManager.
622 // return null pointer on failure, on success return table pointer.
623 TableBase* ConfigurationManagerRW::getVersionedTableByName(const std::string& tableName,
624  TableVersion version,
625  bool looseColumnMatching)
626 {
627  auto it = nameToTableMap_.find(tableName);
628  if(it == nameToTableMap_.end())
629  {
630  __SS__ << "\nCan not find table named '" << tableName
631  << "'\n\n\n\nYou need to load the table before it can be used."
632  << "It probably is missing from the member list of the Table "
633  "Group that was loaded?\n\n\n\n\n"
634  << __E__;
635  __SS_THROW__;
636  }
637  TableBase* table = it->second;
638  theInterface_->get(table,
639  tableName,
640  0,
641  0,
642  false, // fill w/version
643  version,
644  false, // do not reset
645  looseColumnMatching);
646  return table;
647 }
648 
649 //==============================================================================
650 // saveNewTable
651 // saves version, makes the new version the active version, and returns new version
652 TableVersion ConfigurationManagerRW::saveNewTable(const std::string& tableName,
653  TableVersion temporaryVersion,
654  bool makeTemporary) //,
655 // bool saveToScratchVersion)
656 {
657  TableVersion newVersion(temporaryVersion);
658 
659  // set author of version
660  TableBase* table = getTableByName(tableName);
661  table->getTemporaryView(temporaryVersion)->setAuthor(username_);
662  // NOTE: somehow? author is assigned to permanent versions when saved to DBI?
663 
664  if(!makeTemporary) // saveNewVersion makes the new version the active version
665  newVersion = theInterface_->saveNewVersion(table, temporaryVersion);
666  else // make the temporary version active
667  table->setActiveView(newVersion);
668 
669  // if there is a problem, try to recover
670  while(!makeTemporary && !newVersion.isScratchVersion() &&
671  allTableInfo_[tableName].versions_.find(newVersion) !=
672  allTableInfo_[tableName].versions_.end())
673  {
674  __COUT_ERR__ << "What happenened!?? ERROR::: new persistent version v"
675  << newVersion
676  << " already exists!? How is it possible? Retrace your steps and "
677  "tell an admin."
678  << __E__;
679 
680  // create a new temporary version of the target view
681  temporaryVersion = table->createTemporaryView(newVersion);
682 
683  if(newVersion.isTemporaryVersion())
684  newVersion = temporaryVersion;
685  else
686  newVersion = TableVersion::getNextVersion(newVersion);
687 
688  __COUT_WARN__ << "Attempting to recover and use v" << newVersion << __E__;
689 
690  if(!makeTemporary) // saveNewVersion makes the new version the active version
691  newVersion =
692  theInterface_->saveNewVersion(table, temporaryVersion, newVersion);
693  else // make the temporary version active
694  table->setActiveView(newVersion);
695  }
696 
697  if(newVersion.isInvalid())
698  {
699  __SS__ << "Something went wrong saving the new version v" << newVersion
700  << ". What happened?! (duplicates? database error?)" << __E__;
701  __COUT_ERR__ << "\n" << ss.str();
702  __SS_THROW__;
703  }
704 
705  // update allTableInfo_ with the new version
706  allTableInfo_[tableName].versions_.insert(newVersion);
707 
708  __COUT__ << "New version added to info " << newVersion << __E__;
709 
710  return newVersion;
711 }
712 
713 //==============================================================================
714 // eraseTemporaryVersion
715 // if version is invalid then erases ALL temporary versions
716 //
717 // maintains allTableInfo_ also while erasing
718 void ConfigurationManagerRW::eraseTemporaryVersion(const std::string& tableName,
719  TableVersion targetVersion)
720 {
721  TableBase* table = getTableByName(tableName);
722 
723  table->trimTemporary(targetVersion);
724 
725  // if allTableInfo_ is not setup, then done
726  if(allTableInfo_.find(tableName) == allTableInfo_.end())
727  return;
728  // else cleanup table info
729 
730  if(targetVersion.isInvalid())
731  {
732  // erase all temporary versions!
733  for(auto it = allTableInfo_[tableName].versions_.begin();
734  it != allTableInfo_[tableName].versions_.end();
735  /*no increment*/)
736  {
737  if(it->isTemporaryVersion())
738  {
739  __COUT__ << "Removing version info: " << *it << __E__;
740  allTableInfo_[tableName].versions_.erase(it++);
741  }
742  else
743  ++it;
744  }
745  }
746  else // erase target version only
747  {
748  __COUT__ << "Removing version info: " << targetVersion << __E__;
749  auto it = allTableInfo_[tableName].versions_.find(targetVersion);
750  if(it == allTableInfo_[tableName].versions_.end())
751  {
752  __COUT__ << "Target version was not found in info versions..." << __E__;
753  return;
754  }
755  allTableInfo_[tableName].versions_.erase(
756  allTableInfo_[tableName].versions_.find(targetVersion));
757  __COUT__ << "Target version was erased from info." << __E__;
758  }
759 }
760 
761 //==============================================================================
762 // clearCachedVersions
763 // clear ALL cached persistent versions (does not erase temporary versions)
764 //
765 // maintains allTableInfo_ also while erasing (trivial, do nothing)
766 void ConfigurationManagerRW::clearCachedVersions(const std::string& tableName)
767 {
768  TableBase* table = getTableByName(tableName);
769 
770  table->trimCache(0);
771 }
772 
773 //==============================================================================
774 // clearAllCachedVersions
775 // clear ALL cached persistent versions (does not erase temporary versions)
776 //
777 // maintains allTableInfo_ also while erasing (trivial, do nothing)
778 void ConfigurationManagerRW::clearAllCachedVersions()
779 {
780  for(auto configInfo : allTableInfo_)
781  configInfo.second.tablePtr_->trimCache(0);
782 }
783 
784 //==============================================================================
785 // copyViewToCurrentColumns
786 TableVersion ConfigurationManagerRW::copyViewToCurrentColumns(
787  const std::string& tableName, TableVersion sourceVersion)
788 {
789  getTableByName(tableName)->reset();
790 
791  // make sure source version is loaded
792  // need to load with loose column rules!
793  TableBase* table =
794  getVersionedTableByName(tableName, TableVersion(sourceVersion), true);
795 
796  // copy from source version to a new temporary version
797  TableVersion newTemporaryVersion =
798  table->copyView(table->getView(), TableVersion(), username_);
799 
800  // update allTableInfo_ with the new version
801  allTableInfo_[tableName].versions_.insert(newTemporaryVersion);
802 
803  return newTemporaryVersion;
804 }
805 
806 //==============================================================================
807 // cacheGroupKey
808 void ConfigurationManagerRW::cacheGroupKey(const std::string& groupName,
809  TableGroupKey key)
810 {
811  allGroupInfo_[groupName].keys_.emplace(key);
812 }
813 
814 //==============================================================================
815 // getGroupInfo
816 // the interface is slow when there are a lot of groups..
817 // so plan is to maintain local cache of recent group info
818 const GroupInfo& ConfigurationManagerRW::getGroupInfo(const std::string& groupName)
819 {
820  // //NOTE: seems like this filter is taking the long amount of time
821  // std::set<std::string /*name*/> fullGroupNames =
822  // theInterface_->getAllTableGroupNames(groupName); //db filter by
823  // group name
824 
825  // so instead caching ourselves...
826  auto it = allGroupInfo_.find(groupName);
827  if(it == allGroupInfo_.end())
828  {
829  __SS__ << "Group name '" << groupName
830  << "' not found in group info! (creating empty info)" << __E__;
831  __COUT_WARN__ << ss.str();
832  //__SS_THROW__;
833  return allGroupInfo_[groupName];
834  }
835  return it->second;
836 }
837 
838 //==============================================================================
839 // findTableGroup
840 // return group with same name and same members and same aliases
841 // else return invalid key
842 //
843 // Note: if aliases, then member alias is matched (not member
844 //
845 // Note: this is taking too long when there are a ton of groups.
846 // Change to going back only a limited number.. (but the order also comes in alpha order
847 // from theInterface_->getAllTableGroupNames which is a problem for choosing
848 // the most recent to check. )
849 TableGroupKey ConfigurationManagerRW::findTableGroup(
850  const std::string& groupName,
851  const std::map<std::string, TableVersion>& groupMemberMap,
852  const std::map<std::string /*name*/, std::string /*alias*/>& groupAliases)
853 {
854  // //NOTE: seems like this filter is taking the long amount of time
855  // std::set<std::string /*name*/> fullGroupNames =
856  // theInterface_->getAllTableGroupNames(groupName); //db filter by
857  // group name
858  const GroupInfo& groupInfo = getGroupInfo(groupName);
859 
860  // std::string name;
861  // TableGroupKey key;
862  std::map<std::string /*name*/, TableVersion /*version*/> compareToMemberMap;
863  std::map<std::string /*name*/, std::string /*alias*/> compareToGroupAliases;
864  bool isDifferent;
865 
866  const unsigned int MAX_DEPTH_TO_CHECK = 20;
867  unsigned int keyMinToCheck = 0;
868 
869  if(groupInfo.keys_.size())
870  keyMinToCheck = groupInfo.keys_.rbegin()->key();
871  if(keyMinToCheck > MAX_DEPTH_TO_CHECK)
872  {
873  keyMinToCheck -= MAX_DEPTH_TO_CHECK;
874  __COUT__ << "Checking groups back to key... " << keyMinToCheck << __E__;
875  }
876  else
877  {
878  keyMinToCheck = 0;
879  __COUT__ << "Checking all groups." << __E__;
880  }
881 
882  // have min key to check, now loop through and check groups
883  // std::string fullName;
884  for(const auto& key : groupInfo.keys_)
885  {
886  // TableGroupKey::getGroupNameAndKey(fullName,name,key);
887 
888  if(key.key() < keyMinToCheck)
889  continue; // skip keys that are too old
890 
891  // fullName = TableGroupKey::getFullGroupString(groupName,key);
892  //
893  // __COUT__ << "checking group... " << fullName << __E__;
894  //
895  // compareToMemberMap =
896  // theInterface_->getTableGroupMembers(fullName);
897 
898  loadTableGroup(groupName,
899  key,
900  false /*doActivate*/,
901  &compareToMemberMap /*memberMap*/,
902  0,
903  0,
904  0,
905  0,
906  0, /*null pointers*/
907  true /*doNotLoadMember*/,
908  0 /*groupTypeString*/,
909  &compareToGroupAliases);
910 
911  isDifferent = false;
912  for(auto& memberPair : groupMemberMap)
913  {
914  //__COUT__ << memberPair.first << " - " << memberPair.second << __E__;
915 
916  if(groupAliases.find(memberPair.first) != groupAliases.end())
917  {
918  // handle this table as alias, not version
919  if(compareToGroupAliases.find(memberPair.first) ==
920  compareToGroupAliases.end() || // alias is missing
921  groupAliases.at(memberPair.first) !=
922  compareToGroupAliases.at(memberPair.first))
923  { // then different
924  //__COUT__ << "alias mismatch found!" << __E__;
925  isDifferent = true;
926  break;
927  }
928  else
929  continue;
930  } // else check if compareTo group is using an alias for table
931  else if(compareToGroupAliases.find(memberPair.first) !=
932  compareToGroupAliases.end())
933  {
934  // then different
935  //__COUT__ << "alias mismatch found!" << __E__;
936  isDifferent = true;
937  break;
938 
939  } // else handle as table version comparison
940  else if(compareToMemberMap.find(memberPair.first) ==
941  compareToMemberMap.end() || // name is missing
942  memberPair.second !=
943  compareToMemberMap.at(memberPair.first)) // or version mismatch
944  { // then different
945  //__COUT__ << "mismatch found!" << __E__;
946  isDifferent = true;
947  break;
948  }
949  }
950  if(isDifferent)
951  continue;
952 
953  // check member size for exact match
954  if(groupMemberMap.size() != compareToMemberMap.size())
955  continue; // different size, so not same (groupMemberMap is a subset of
956  // memberPairs)
957 
958  __COUT__ << "Found exact match with key: " << key << __E__;
959  // else found an exact match!
960  return key;
961  }
962  __COUT__ << "No match found - this group is new!" << __E__;
963  // if here, then no match found
964  return TableGroupKey(); // return invalid key
965 }
966 
967 //==============================================================================
968 // saveNewTableGroup
969 // saves new group and returns the new group key
970 // if previousVersion is provided, attempts to just bump that version
971 // else, bumps latest version found in db
972 //
973 // Note: groupMembers map will get modified with group metadata table version
974 TableGroupKey ConfigurationManagerRW::saveNewTableGroup(
975  const std::string& groupName,
976  std::map<std::string, TableVersion>& groupMembers,
977  const std::string& groupComment,
978  std::map<std::string /*table*/, std::string /*alias*/>* groupAliases)
979 {
980  // steps:
981  // determine new group key
982  // verify group members
983  // verify groupNameWithKey
984  // verify store
985 
986  if(groupMembers.size() == 0) // do not allow empty groups
987  {
988  __SS__ << "Empty group member list. Can not create a group without members!"
989  << __E__;
990  __SS_THROW__;
991  }
992 
993  // determine new group key
994  TableGroupKey newKey =
995  TableGroupKey::getNextKey(theInterface_->findLatestGroupKey(groupName));
996 
997  __COUT__ << "New Key for group: " << groupName << " found as " << newKey << __E__;
998 
999  // verify group members
1000  // - use all table info
1001  std::map<std::string, TableInfo> allCfgInfo = getAllTableInfo();
1002  for(auto& memberPair : groupMembers)
1003  {
1004  // check member name
1005  if(allCfgInfo.find(memberPair.first) == allCfgInfo.end())
1006  {
1007  __COUT_ERR__ << "Group member \"" << memberPair.first
1008  << "\" not found in database!";
1009 
1010  if(groupMetadataTable_.getTableName() == memberPair.first)
1011  {
1012  __COUT_WARN__
1013  << "Looks like this is the groupMetadataTable_ '"
1014  << ConfigurationInterface::GROUP_METADATA_TABLE_NAME
1015  << ".' Note that this table is added to the member map when groups "
1016  "are saved."
1017  << "It should not be part of member map when calling this function."
1018  << __E__;
1019  __COUT__ << "Attempting to recover." << __E__;
1020  groupMembers.erase(groupMembers.find(memberPair.first));
1021  }
1022  else
1023  {
1024  __SS__ << ("Group member not found!") << __E__;
1025  __SS_THROW__;
1026  }
1027  }
1028  // check member version
1029  if(allCfgInfo[memberPair.first].versions_.find(memberPair.second) ==
1030  allCfgInfo[memberPair.first].versions_.end())
1031  {
1032  __SS__ << "Group member \"" << memberPair.first << "\" version \""
1033  << memberPair.second << "\" not found in database!";
1034  __SS_THROW__;
1035  }
1036  } // end verify members
1037 
1038  // verify group aliases
1039  if(groupAliases)
1040  {
1041  for(auto& aliasPair : *groupAliases)
1042  {
1043  // check for alias table in member names
1044  if(groupMembers.find(aliasPair.first) == groupMembers.end())
1045  {
1046  __COUT_ERR__ << "Group member \"" << aliasPair.first
1047  << "\" not found in group member map!";
1048 
1049  __SS__ << ("Alias table not found in member list!") << __E__;
1050  __SS_THROW__;
1051  }
1052  }
1053  } // end verify group aliases
1054 
1055  // verify groupNameWithKey and attempt to store
1056  try
1057  {
1058  // save meta data for group; reuse groupMetadataTable_
1059  std::string groupAliasesString = "";
1060  if(groupAliases)
1061  groupAliasesString = StringMacros::mapToString(
1062  *groupAliases, "," /*primary delimeter*/, ":" /*secondary delimeter*/);
1063  __COUT__ << "Metadata: " << username_ << " " << time(0) << " " << groupComment
1064  << " " << groupAliasesString << __E__;
1065 
1066  // to compensate for unusual errors upstream, make sure the metadata table has one
1067  // row
1068  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
1069  groupMetadataTable_.getViewP()->deleteRow(0);
1070  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
1071  groupMetadataTable_.getViewP()->addRow();
1072 
1073  // columns are uid,comment,author,time
1074  groupMetadataTable_.getViewP()->setValue(
1075  groupAliasesString, 0, ConfigurationManager::METADATA_COL_ALIASES);
1076  groupMetadataTable_.getViewP()->setValue(
1077  groupComment, 0, ConfigurationManager::METADATA_COL_COMMENT);
1078  groupMetadataTable_.getViewP()->setValue(
1079  username_, 0, ConfigurationManager::METADATA_COL_AUTHOR);
1080  groupMetadataTable_.getViewP()->setValue(
1081  time(0), 0, ConfigurationManager::METADATA_COL_TIMESTAMP);
1082 
1083  // set version to first available persistent version
1084  groupMetadataTable_.getViewP()->setVersion(TableVersion::getNextVersion(
1085  theInterface_->findLatestVersion(&groupMetadataTable_)));
1086 
1087  // groupMetadataTable_.print();
1088 
1089  theInterface_->saveActiveVersion(&groupMetadataTable_);
1090 
1091  // force groupMetadataTable_ to be a member for the group
1092  groupMembers[groupMetadataTable_.getTableName()] =
1093  groupMetadataTable_.getViewVersion();
1094 
1095  theInterface_->saveTableGroup(
1096  groupMembers, TableGroupKey::getFullGroupString(groupName, newKey));
1097  __COUT__ << "Created table group: " << groupName << ":" << newKey << __E__;
1098  }
1099  catch(std::runtime_error& e)
1100  {
1101  __COUT_ERR__ << "Failed to create table group: " << groupName << ":" << newKey
1102  << __E__;
1103  __COUT_ERR__ << "\n\n" << e.what() << __E__;
1104  throw;
1105  }
1106  catch(...)
1107  {
1108  __COUT_ERR__ << "Failed to create table group: " << groupName << ":" << newKey
1109  << __E__;
1110  throw;
1111  }
1112 
1113  // store cache of recent groups
1114  cacheGroupKey(groupName, newKey);
1115 
1116  // at this point succeeded!
1117  return newKey;
1118 }
1119 
1120 //==============================================================================
1121 // saveNewBackbone
1122 // makes the new version the active version and returns new version number
1123 // INVALID will give a new backbone from mockup
1124 TableVersion ConfigurationManagerRW::saveNewBackbone(TableVersion temporaryVersion)
1125 {
1126  __COUT_INFO__ << "Creating new backbone from temporary version " << temporaryVersion
1127  << __E__;
1128 
1129  // find common available temporary version among backbone members
1130  TableVersion newVersion(TableVersion::DEFAULT);
1131  TableVersion retNewVersion;
1132  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
1133  for(auto& name : backboneMemberNames)
1134  {
1135  retNewVersion = ConfigurationManager::getTableByName(name)->getNextVersion();
1136  __COUT__ << "New version for backbone member (" << name << "): " << retNewVersion
1137  << __E__;
1138  if(retNewVersion > newVersion)
1139  newVersion = retNewVersion;
1140  }
1141 
1142  __COUT__ << "Common new backbone version found as " << newVersion << __E__;
1143 
1144  // create new views from source temporary version
1145  for(auto& name : backboneMemberNames)
1146  {
1147  // saveNewVersion makes the new version the active version
1148  retNewVersion = getConfigurationInterface()->saveNewVersion(
1149  getTableByName(name), temporaryVersion, newVersion);
1150  if(retNewVersion != newVersion)
1151  {
1152  __SS__ << "Failure! New view requested was " << newVersion
1153  << ". Mismatched new view created: " << retNewVersion << __E__;
1154  __COUT_ERR__ << ss.str();
1155  __SS_THROW__;
1156  }
1157  }
1158 
1159  return newVersion;
1160 }
1161 
1162 //==============================================================================
1164 {
1165  // //test creating table group with author, create time, and comment
1166  // {
1167  // __COUT__ << __E__;
1168  //
1169  // std::string groupName = "testGroup";
1170  // TableGroupKey newKey;
1171  // //TableGroupMetadata
1172  //
1173  // try
1174  // {
1175  // {
1176  // std::map<std::string, TableVersion> members;
1177  // members["ARTDAQAggregatorTable"] = TableVersion(1);
1178  //
1179  // //TableGroupKey
1180  // // saveNewTableGroup
1181  // // (const std::string &groupName, const std::map<std::string,
1182  // // TableVersion> &groupMembers, TableGroupKey
1183  // previousVersion=TableGroupKey()); newKey =
1184  // saveNewTableGroup(groupName,members);
1185  // }
1186  //
1187  // //std::map<std::string, TableVersion >
1188  // // loadTableGroup
1189  // // (const std::string &configGroupName,
1190  // // TableGroupKey configGroupKey, bool doActivate=false, ProgressBar*
1191  // progressBar=0, std::string *accumulateWarnings=0);
1192  // {
1193  // std::map<std::string, TableVersion > memberMap =
1194  // loadTableGroup(groupName,newKey);
1195  // __COUT__ << "Group members:" << __E__;
1196  // for(const auto &member: memberMap)
1197  // __COUT__ << member.first << " " << member.second << __E__;
1198  // }
1199  //
1200  //
1201  //
1202  // //do it again
1203  // {
1204  // std::map<std::string, TableVersion> members;
1205  // members["ARTDAQAggregatorTable"] = TableVersion(1);
1206  //
1207  // //TableGroupKey
1208  // // saveNewTableGroup
1209  // // (const std::string &groupName, const std::map<std::string,
1210  // // TableVersion> &groupMembers, TableGroupKey
1211  // previousVersion=TableGroupKey()); newKey =
1212  // saveNewTableGroup(groupName,members);
1213  // }
1214  //
1215  // //std::map<std::string, TableVersion >
1216  // // loadTableGroup
1217  // // (const std::string &configGroupName,
1218  // // TableGroupKey configGroupKey, bool doActivate=false, ProgressBar*
1219  // progressBar=0, std::string *accumulateWarnings=0);
1220  // {
1221  // std::map<std::string, TableVersion > memberMap =
1222  // loadTableGroup(groupName,newKey);
1223  // __COUT__ << "Group members:" << __E__;
1224  // for(const auto &member: memberMap)
1225  // __COUT__ << member.first << " " << member.second << __E__;
1226  // }
1227  //
1228  //
1229  // }
1230  // catch(std::runtime_error &e)
1231  // {
1232  // __COUT_ERR__ << "Failed to create table group: " << groupName << ":" <<
1233  // newKey
1234  //<< __E__;
1235  // __COUT_ERR__ << "\n\n" << e.what() << __E__;
1236  // }
1237  // catch(...)
1238  // {
1239  // __COUT_ERR__ << "Failed to create table group: " << groupName << ":" <<
1240  // newKey
1241  //<< __E__;
1242  // }
1243  //
1244  // return;
1245  // }
1246 
1247  // //test creating table group and reading
1248  // {
1249  // __COUT__ << __E__;
1250  //
1251  // auto gcfgs = theInterface_->getAllTableGroupNames();
1252  // __COUT__ << "Global table size: " << gcfgs.size() << __E__;
1253  // for(auto &g:gcfgs)
1254  // {
1255  // __COUT__ << "Global table " << g << __E__;
1256  // auto gcMap = theInterface_->getTableGroupMembers(g, true
1258  //
1259  // for(auto &cv:gcMap)
1260  // __COUT__ << "\tMember table " << cv.first << ":" << cv.second <<
1261  // __E__;
1262  // }
1263  //
1264  // auto cfgs = theInterface_->getAllTableNames();
1265  // __COUT__ << "Sub-table size: " << cfgs.size() << __E__;
1266  // for(auto &c:cfgs)
1267  // {
1268  // __COUT__ << "table " << c << __E__;
1269  // auto vs = theInterface_->getVersions(getTableByName(c));
1270  // for(auto &v:vs)
1271  // __COUT__ << "\tversion " << v << __E__;
1272  // }
1273  //
1274  // if(0) //create a table group (storeGlobalConfiguration)
1275  // {
1276  // //storeGlobalConfiguration with latest of each
1277  // std::map<std::string /*name*/, TableVersion /*version*/> gcMap;
1278  //
1279  // for(auto &c:cfgs) //for each sub-table, take latest version
1280  // {
1281  // auto vs = theInterface_->getVersions(getTableByName(c));
1282  // if(1 && vs.rbegin() != vs.rend()) //create latest!
1283  // {
1284  // gcMap[c] = *(vs.rbegin());
1285  // __COUT__ << "Adding table " << c << ":" << gcMap[c] << __E__;
1286  // }
1287  // else if(vs.begin() != vs.end()) //create oldest!
1288  // {
1289  // gcMap[c] = *(vs.begin());
1290  // __COUT__ << "Adding table " << c << ":" << gcMap[c] << __E__;
1291  // }
1292  // }
1293  //
1294  // int i = 0;
1295  // bool done = false;
1296  // char gcname[100];
1297  // bool found;
1298  // while(!done && i<1)
1299  // {
1300  // do //avoid conflicting global table names
1301  // {
1302  // found = false;
1303  // sprintf(gcname,"GConfig_v%d",i++);
1304  // for(auto &g:gcfgs)
1305  // if(g == gcname) {found = true; break;}
1306  // }
1307  // while(found);
1308  // __COUT__ << "Trying Global table: " << gcname<< __E__;
1309  //
1310  // try
1311  // {
1312  // theInterface_->saveTableGroup(gcMap,gcname);
1313  // done = true;
1314  // __COUT__ << "Created Global table: " << gcname<< __E__;
1315  // }
1316  // catch(...) {++i;} //repeat names are not allowed, so increment name
1317  // }
1318  //
1319  // }
1320  //
1321  // //return;
1322  // }
1323  //
1324  // this is to test table tree
1325  try
1326  {
1327  __COUT__ << "Loading table..." << __E__;
1328  loadTableGroup("FETest", TableGroupKey(2)); // Context_1
1329  ConfigurationTree t = getNode("/FETable/DEFAULT/FrontEndType");
1330 
1331  std::string v;
1332 
1333  __COUT__ << __E__;
1334  t.getValue(v);
1335  __COUT__ << "Value: " << v << __E__;
1336  __COUT__ << "Value index: " << t.getValue<int>() << __E__;
1337 
1338  return;
1339 
1340  // ConfigurationTree t = getNode("XDAQContextTable");
1341  // ConfigurationTree t = getNode("/FETable/OtsUDPFSSR3/FrontEndType");
1342  // ConfigurationTree t = getNode("/FETable").getNode("OtsUDPFSSR3");
1343  // ConfigurationTree t = getNode("/XDAQContextTable/testContext/");
1344  //
1345  // __COUT__ << __E__;
1346  // t.getValue(v);
1347  // __COUT__ << "Value: " << v << __E__;
1348  //
1349  // if(!t.isValueNode())
1350  // {
1351  // auto C = t.getChildrenNames();
1352  // for(auto &c: C)
1353  // __COUT__ << "\t+ " << c << __E__;
1354  //
1355  // std::stringstream ss;
1356  // t.print(-1,ss);
1357  // __COUT__ << "\n" << ss.str() << __E__;
1358  //
1359  // try
1360  // {
1361  // ConfigurationTree tt = t.getNode("OtsUDPFSSR3");
1362  // tt.getValue(v);
1363  // __COUT__ << "Value: " << v << __E__;
1364  //
1365  // C = tt.getChildrenNames();
1366  // for(auto &c: C)
1367  // __COUT__ << "\t+ " << c << __E__;
1368  // }
1369  // catch(...)
1370  // {
1371  // __COUT__ << "Failed to find extra node." << __E__;
1372  // }
1373  // }
1374  }
1375  catch(...)
1376  {
1377  __COUT__ << "Failed to load table..." << __E__;
1378  }
1379 }