otsdaq  v2_04_01
ConfigurationManager.cc
1 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
2 #include "artdaq/Application/LoadParameterSet.hh"
3 #include "otsdaq-core/ConfigurationInterface/ConfigurationInterface.h" //All configurable objects are included here
4 #include "otsdaq-core/ProgressBar/ProgressBar.h"
5 
6 #include <fstream> // std::ofstream
7 
8 #include "otsdaq-core/TableCore/TableGroupKey.h"
9 
10 using namespace ots;
11 
12 #undef __MF_SUBJECT__
13 #define __MF_SUBJECT__ "ConfigurationManager"
14 
15 const std::string ConfigurationManager::READONLY_USER = "READONLY_USER";
16 
17 const std::string ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME = "XDAQContextTable";
18 const std::string ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME =
19  "XDAQApplicationTable";
20 const std::string ConfigurationManager::GROUP_ALIASES_TABLE_NAME = "GroupAliasesTable";
21 const std::string ConfigurationManager::VERSION_ALIASES_TABLE_NAME =
22  "VersionAliasesTable";
23 
24 // added env check for otsdaq_flatten_active_to_version to function
25 const std::string ConfigurationManager::ACTIVE_GROUPS_FILENAME =
26  ((getenv("SERVICE_DATA_PATH") == NULL)
27  ? (std::string(__ENV__("USER_DATA")) + "/ServiceData")
28  : (std::string(__ENV__("SERVICE_DATA_PATH")))) +
29  "/ActiveTableGroups.cfg";
30 const std::string ConfigurationManager::ALIAS_VERSION_PREAMBLE = "ALIAS:";
31 const std::string ConfigurationManager::SCRATCH_VERSION_ALIAS = "Scratch";
32 
33 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT = "Context";
34 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE = "Backbone";
35 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE = "Iterate";
36 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION = "Configuration";
37 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_UNKNOWN = "Unknown";
38 
39 const uint8_t ConfigurationManager::METADATA_COL_ALIASES = 1;
40 const uint8_t ConfigurationManager::METADATA_COL_COMMENT = 2;
41 const uint8_t ConfigurationManager::METADATA_COL_AUTHOR = 3;
42 const uint8_t ConfigurationManager::METADATA_COL_TIMESTAMP = 4;
43 
44 const std::set<std::string> ConfigurationManager::contextMemberNames_ = {
45  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME,
46  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
47  "XDAQApplicationPropertyTable",
48  "DesktopIconTable",
49  "MessageFacilityTable",
50  "GatewaySupervisorTable",
51  "StateMachineTable",
52  "DesktopWindowParameterTable"};
53 const std::set<std::string> ConfigurationManager::backboneMemberNames_ = {
54  ConfigurationManager::GROUP_ALIASES_TABLE_NAME,
55  ConfigurationManager::VERSION_ALIASES_TABLE_NAME};
56 const std::set<std::string> ConfigurationManager::iterateMemberNames_ = {
57  "IterateTable",
58  "IterationPlanTable",
59  "IterationTargetTable",
60  /*command specific tables*/ "IterationCommandBeginLabelTable",
61  "IterationCommandChooseFSMTable",
62  "IterationCommandConfigureAliasTable",
63  "IterationCommandConfigureGroupTable",
64  "IterationCommandExecuteFEMacroTable",
65  "IterationCommandExecuteMacroTable",
66  "IterationCommandMacroDimensionalLoopTable",
67  "IterationCommandMacroDimensionalLoopParameterTable",
68  "IterationCommandModifyGroupTable",
69  "IterationCommandRepeatLabelTable",
70  "IterationCommandRunTable"};
71 
72 //==============================================================================
73 ConfigurationManager::ConfigurationManager(bool initForWriteAccess /*=false*/,
74  bool doInitializeFromFhicl /*=false*/)
75  : username_(ConfigurationManager::READONLY_USER)
76  , theInterface_(0)
77  , theConfigurationTableGroupKey_(0)
78  , theContextTableGroupKey_(0)
79  , theBackboneTableGroupKey_(0)
80  , theConfigurationTableGroup_("")
81  , theContextTableGroup_("")
82  , theBackboneTableGroup_("")
83 {
84  theInterface_ = ConfigurationInterface::getInstance(false); // false to use artdaq DB
85 
86  // initialize special group metadata table
87  {
88  // Note: "TableGroupMetadata" should never be in conflict
89  // because all other tables end in "...Table"
90 
91  // This is a table called TableGroupMetadata
92  // with 4 fields:
93  // - GroupAliases
94  // - GroupAuthor
95  // - GroupCreationTime
96  // - CommentDescription
97 
98  groupMetadataTable_.setTableName(
99  ConfigurationInterface::GROUP_METADATA_TABLE_NAME);
100  std::vector<TableViewColumnInfo>* colInfo =
101  groupMetadataTable_.getMockupViewP()->getColumnsInfoP();
102 
103  colInfo->push_back(TableViewColumnInfo(
104  TableViewColumnInfo::TYPE_UID, // just to make init() happy
105  "UnusedUID",
106  "UNUSED_UID",
107  TableViewColumnInfo::DATATYPE_NUMBER,
108  "",
109  0));
110  colInfo->push_back(TableViewColumnInfo(TableViewColumnInfo::TYPE_DATA,
111  "GroupAliases",
112  "GROUP_ALIASES",
113  TableViewColumnInfo::DATATYPE_STRING,
114  "",
115  0));
116  colInfo->push_back(TableViewColumnInfo(
117  TableViewColumnInfo::TYPE_COMMENT, // just to make init() happy
118  TableViewColumnInfo::COL_NAME_COMMENT,
119  "COMMENT_DESCRIPTION",
120  TableViewColumnInfo::DATATYPE_STRING,
121  "",
122  0));
123  colInfo->push_back(TableViewColumnInfo(
124  TableViewColumnInfo::TYPE_AUTHOR, // just to make init() happy
125  "GroupAuthor",
126  "AUTHOR",
127  TableViewColumnInfo::DATATYPE_STRING,
128  "",
129  0));
130  colInfo->push_back(TableViewColumnInfo(TableViewColumnInfo::TYPE_TIMESTAMP,
131  "GroupCreationTime",
132  "GROUP_CREATION_TIME",
133  TableViewColumnInfo::DATATYPE_TIME,
134  "",
135  0));
136  auto tmpVersion = groupMetadataTable_.createTemporaryView();
137  groupMetadataTable_.setActiveView(tmpVersion);
138  // only need this one and only row for all time
139  groupMetadataTable_.getViewP()->addRow();
140  }
141 
142  if(doInitializeFromFhicl)
143  {
144  // create tables and fill based on fhicl
145  initializeFromFhicl(__ENV__("CONFIGURATION_INIT_FCL"));
146  return;
147  }
148  // else do normal init
149  init(0 /*accumulatedErrors*/, initForWriteAccess);
150 
151 } // end constructor()
152 
153 //==============================================================================
154 ConfigurationManager::ConfigurationManager(const std::string& username)
155  : ConfigurationManager(true /*initForWriteAccess*/)
156 {
157  __COUT_INFO__ << "Private constructor for write access called." << __E__;
158  username_ = username;
159 } // end constructor(username)
160 
161 //==============================================================================
162 ConfigurationManager::~ConfigurationManager() { destroy(); }
163 
164 //==============================================================================
165 // init
166 // if accumulatedErrors is not null.. fill it with errors
167 // else throw errors (but do not ask restoreActiveTableGroups to throw errors)
168 void ConfigurationManager::init(std::string* accumulatedErrors,
169  bool initForWriteAccess /*= false*/)
170 {
171  // if(accumulatedErrors)
172  // *accumulatedErrors = "";
173 
174  // destroy();
175 
176  // once Interface is false (using artdaq db) ..
177  // then can test (configurationInterface_->getMode() == false)
178  {
179  try
180  {
181  __COUTV__(username_);
182 
183  restoreActiveTableGroups(
184  accumulatedErrors ? true : false /*throwErrors*/,
185  "" /*pathToActiveGroupsFile*/,
186  // if write access, then load everything
187  (username_ == ConfigurationManager::READONLY_USER)
188  ? (!initForWriteAccess) // important to consider initForWriteAccess
189  // because this may be called before
190  // username_ is properly initialized
191  : false /*onlyLoadIfBackboneOrContext*/);
192  }
193  catch(std::runtime_error& e)
194  {
195  if(accumulatedErrors)
196  *accumulatedErrors += e.what();
197  else
198  throw;
199  }
200  }
201 } // end init()
202 
203 //==============================================================================
204 // restoreActiveTableGroups
205 // load the active groups from file
206 // Note: this should be used by the Supervisor to maintain
207 // the same configurationGroups surviving software system restarts
208 void ConfigurationManager::restoreActiveTableGroups(
209  bool throwErrors,
210  const std::string& pathToActiveGroupsFile,
211  bool onlyLoadIfBackboneOrContext /*= false*/)
212 {
213  destroyTableGroup("", true); // deactivate all
214 
215  std::string fn =
216  pathToActiveGroupsFile == "" ? ACTIVE_GROUPS_FILENAME : pathToActiveGroupsFile;
217  FILE* fp = fopen(fn.c_str(), "r");
218 
219  __COUT__ << "ACTIVE_GROUPS_FILENAME = " << fn << __E__;
220  __COUT__ << "ARTDAQ_DATABASE_URI = " << std::string(__ENV__("ARTDAQ_DATABASE_URI"))
221  << __E__;
222 
223  if(!fp)
224  {
225  __COUT_WARN__ << "No active groups file found at " << fn << __E__;
226  return;
227  }
228 
229  //__COUT__ << "throwErrors: " << throwErrors << __E__;
230 
231  char tmp[500];
232  char strVal[500];
233 
234  std::string groupName;
235  std::string errorStr = "";
236  bool skip;
237 
238  __SS__;
239 
240  while(fgets(tmp, 500, fp)) // for(int i=0;i<4;++i)
241  {
242  // fgets(tmp,500,fp);
243 
244  skip = false;
245  sscanf(tmp, "%s", strVal); // sscanf to remove '\n'
246  for(unsigned int j = 0; j < strlen(strVal); ++j)
247  if(!((strVal[j] >= 'a' && strVal[j] <= 'z') ||
248  (strVal[j] >= 'A' && strVal[j] <= 'Z') ||
249  (strVal[j] >= '0' && strVal[j] <= '9')))
250  {
251  strVal[j] = '\0';
252  __COUT_INFO__ << "Illegal character found, so skipping!" << __E__;
253 
254  skip = true;
255  break;
256  }
257 
258  if(skip)
259  continue;
260 
261  groupName = strVal;
262  fgets(tmp, 500, fp);
263  sscanf(tmp, "%s", strVal); // sscanf to remove '\n'
264 
265  for(unsigned int j = 0; j < strlen(strVal); ++j)
266  if(!((strVal[j] >= '0' && strVal[j] <= '9')))
267  {
268  strVal[j] = '\0';
269 
270  if(groupName.size() > 3) // notify if seems like a real group name
271  __COUT_INFO__
272  << "Skipping active group with illegal character in name."
273  << __E__;
274 
275  skip = true;
276  break;
277  }
278 
279  if(skip)
280  continue;
281 
282  try
283  {
284  TableGroupKey::getFullGroupString(groupName, TableGroupKey(strVal));
285  }
286  catch(...)
287  {
288  __COUT__ << "illegal group according to TableGroupKey::getFullGroupString..."
289  << __E__;
290  skip = true;
291  }
292 
293  if(skip)
294  continue;
295 
296  try
297  {
298  // load and doActivate
299  loadTableGroup(
300  groupName,
301  TableGroupKey(strVal),
302  true /*doActivate*/,
303  0 /*groupMembers*/,
304  0 /*progressBar*/,
305  0 /*accumulateWarnings = 0*/,
306  0 /*groupComment = 0*/,
307  0 /*groupAuthor = 0*/,
308  0 /*groupCreateTime = 0*/,
309  0 /*doNotLoadMember = false*/,
310  0 /*groupTypeString = 0*/,
311  0 /*groupAliases = 0*/,
312  onlyLoadIfBackboneOrContext /*onlyLoadIfBackboneOrContext = false*/
313  );
314  }
315  catch(std::runtime_error& e)
316  {
317  ss << "Failed to load group in ConfigurationManager::init() with name '"
318  << groupName << "(" << strVal << ")'" << __E__;
319  ss << e.what() << __E__;
320 
321  errorStr += ss.str();
322  }
323  catch(...)
324  {
325  ss << "Failed to load group in ConfigurationManager::init() with name '"
326  << groupName << "(" << strVal << ")'" << __E__;
327 
328  errorStr += ss.str();
329  }
330  }
331 
332  fclose(fp);
333 
334  if(throwErrors && errorStr != "")
335  {
336  __COUT_INFO__ << "\n" << ss.str();
337  __THROW__(errorStr);
338  }
339  else if(errorStr != "")
340  __COUT_INFO__ << "\n" << ss.str();
341 
342 } // end restoreActiveTableGroups()
343 
344 //==============================================================================
345 // destroyTableGroup
346 // destroy all if theGroup == ""
347 // else destroy that group
348 // if onlyDeactivate, then don't delete, just deactivate view
349 void ConfigurationManager::destroyTableGroup(const std::string& theGroup,
350  bool onlyDeactivate)
351 {
352  // delete
353  bool isContext = theGroup == "" || theGroup == theContextTableGroup_;
354  bool isBackbone = theGroup == "" || theGroup == theBackboneTableGroup_;
355  bool isIterate = theGroup == "" || theGroup == theIterateTableGroup_;
356  bool isConfiguration = theGroup == "" || theGroup == theConfigurationTableGroup_;
357 
358  if(!isContext && !isBackbone && !isIterate && !isConfiguration)
359  {
360  __SS__ << "Invalid configuration group to destroy: " << theGroup << __E__;
361  __COUT_ERR__ << ss.str();
362  __SS_THROW__;
363  }
364 
365  std::string dbgHeader = onlyDeactivate ? "Deactivating" : "Destroying";
366  if(theGroup != "")
367  {
368  if(isContext)
369  __COUT__ << dbgHeader << " Context group: " << theGroup << __E__;
370  if(isBackbone)
371  __COUT__ << dbgHeader << " Backbone group: " << theGroup << __E__;
372  if(isIterate)
373  __COUT__ << dbgHeader << " Iterate group: " << theGroup << __E__;
374  if(isConfiguration)
375  __COUT__ << dbgHeader << " Configuration group: " << theGroup << __E__;
376  }
377 
378  std::set<std::string>::const_iterator contextFindIt, backboneFindIt, iterateFindIt;
379  for(auto it = nameToTableMap_.begin(); it != nameToTableMap_.end();
380  /*no increment*/)
381  {
382  contextFindIt = contextMemberNames_.find(it->first);
383  backboneFindIt = backboneMemberNames_.find(it->first);
384  iterateFindIt = iterateMemberNames_.find(it->first);
385  if(theGroup == "" ||
386  ((isContext && contextFindIt != contextMemberNames_.end()) ||
387  (isBackbone && backboneFindIt != backboneMemberNames_.end()) ||
388  (isIterate && iterateFindIt != iterateMemberNames_.end()) ||
389  (!isContext && !isBackbone && contextFindIt == contextMemberNames_.end() &&
390  backboneFindIt == backboneMemberNames_.end() &&
391  iterateFindIt == iterateMemberNames_.end())))
392  {
393  //__COUT__ << "\t" << it->first << __E__;
394  // if(it->second->isActive())
395  // __COUT__ << "\t\t..._v" << it->second->getViewVersion() << __E__;
396 
397  if(onlyDeactivate) // only deactivate
398  {
399  it->second->deactivate();
400  ++it;
401  }
402  else // else, delete/erase
403  {
404  delete it->second;
405  nameToTableMap_.erase(it++);
406  }
407  }
408  else
409  ++it;
410  }
411 
412  if(isConfiguration)
413  {
414  theConfigurationTableGroup_ = "";
415  if(theConfigurationTableGroupKey_ != 0)
416  {
417  __COUT__ << "Destroying Configuration Key: "
418  << *theConfigurationTableGroupKey_ << __E__;
419  theConfigurationTableGroupKey_.reset();
420  }
421 
422  // theDACStreams_.clear();
423  }
424  if(isBackbone)
425  {
426  theBackboneTableGroup_ = "";
427  if(theBackboneTableGroupKey_ != 0)
428  {
429  __COUT__ << "Destroying Backbone Key: " << *theBackboneTableGroupKey_
430  << __E__;
431  theBackboneTableGroupKey_.reset();
432  }
433  }
434  if(isIterate)
435  {
436  theIterateTableGroup_ = "";
437  if(theIterateTableGroupKey_ != 0)
438  {
439  __COUT__ << "Destroying Iterate Key: " << *theIterateTableGroupKey_ << __E__;
440  theIterateTableGroupKey_.reset();
441  }
442  }
443  if(isContext)
444  {
445  theContextTableGroup_ = "";
446  if(theContextTableGroupKey_ != 0)
447  {
448  __COUT__ << "Destroying Context Key: " << *theContextTableGroupKey_ << __E__;
449  theContextTableGroupKey_.reset();
450  }
451  }
452 }
453 
454 //==============================================================================
455 void ConfigurationManager::destroy(void)
456 {
457  // NOTE: Moved to ConfigurationGUISupervisor [FIXME is this correct?? should we use
458  // shared_ptr??]
459  // if( ConfigurationInterface::getInstance(true) != 0 )
460  // delete theInterface_;
461  destroyTableGroup();
462 }
463 
464 //==============================================================================
465 // convertGroupTypeIdToName
466 // return translation:
467 // 0 for context
468 // 1 for backbone
469 // 2 for configuration (others)
470 const std::string& ConfigurationManager::convertGroupTypeIdToName(int groupTypeId)
471 {
472  return groupTypeId == CONTEXT_TYPE
473  ? ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT
474  : (groupTypeId == BACKBONE_TYPE
475  ? ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE
476  : (groupTypeId == ITERATE_TYPE
477  ? ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE
478  : ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION));
479 }
480 
481 //==============================================================================
482 // getTypeOfGroup
483 // return
484 // CONTEXT_TYPE for context
485 // BACKBONE_TYPE for backbone
486 // ITERATE_TYPE for iterate
487 // CONFIGURATION_TYPE for configuration (others)
488 int ConfigurationManager::getTypeOfGroup(
489  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap)
490 {
491  bool isContext = true;
492  bool isBackbone = true;
493  bool isIterate = true;
494  bool inGroup;
495  bool inContext = false;
496  bool inBackbone = false;
497  bool inIterate = false;
498  unsigned int matchCount = 0;
499 
500  for(auto& memberPair : memberMap)
501  {
502  //__COUT__ << "Member name: = "<< memberPair.first << __E__;
504  inGroup = false; // check context
505  for(auto& contextMemberString : contextMemberNames_)
506  if(memberPair.first == contextMemberString)
507  {
508  inGroup = true;
509  inContext = true;
510  ++matchCount;
511  break;
512  }
513  if(!inGroup)
514  {
515  isContext = false;
516  if(inContext) // there was a member in context!
517  {
518  __SS__ << "This group is an incomplete match to a Context group.\n";
519  __COUT_ERR__ << "\n" << ss.str();
520  ss << "\nTo be a Context group, the members must exactly match "
521  << "the following members:\n";
522  int i = 0;
523  for(const auto& memberName : contextMemberNames_)
524  ss << ++i << ". " << memberName << "\n";
525  ss << "\nThe members are as follows::\n";
526  i = 0;
527  for(const auto& memberPairTmp : memberMap)
528  ss << ++i << ". " << memberPairTmp.first << "\n";
529  __SS_THROW__;
530  }
531  }
532 
534  inGroup = false; // check backbone
535  for(auto& backboneMemberString : backboneMemberNames_)
536  if(memberPair.first == backboneMemberString)
537  {
538  inGroup = true;
539  inBackbone = true;
540  ++matchCount;
541  break;
542  }
543  if(!inGroup)
544  {
545  isBackbone = false;
546  if(inBackbone) // there was a member in backbone!
547  {
548  __SS__ << "This group is an incomplete match to a Backbone group.\n";
549  __COUT_ERR__ << "\n" << ss.str();
550  ss << "\nTo be a Backbone group, the members must exactly match "
551  << "the following members:\n";
552  int i = 0;
553  for(auto& memberName : backboneMemberNames_)
554  ss << ++i << ". " << memberName << "\n";
555  ss << "\nThe members are as follows::\n";
556  i = 0;
557  for(const auto& memberPairTmp : memberMap)
558  ss << ++i << ". " << memberPairTmp.first << "\n";
559  //__COUT_ERR__ << "\n" << ss.str();
560  __SS_THROW__;
561  }
562  }
563 
565  inGroup = false; // check iterate
566  for(auto& iterateMemberString : iterateMemberNames_)
567  if(memberPair.first == iterateMemberString)
568  {
569  inGroup = true;
570  inIterate = true;
571  ++matchCount;
572  break;
573  }
574  if(!inGroup)
575  {
576  isIterate = false;
577  if(inIterate) // there was a member in iterate!
578  {
579  __SS__ << "This group is an incomplete match to a Iterate group.\n";
580  __COUT_ERR__ << "\n" << ss.str();
581  ss << "\nTo be a Iterate group, the members must exactly match "
582  << "the following members:\n";
583  int i = 0;
584  for(auto& memberName : iterateMemberNames_)
585  ss << ++i << ". " << memberName << "\n";
586  ss << "\nThe members are as follows::\n";
587  i = 0;
588  for(const auto& memberPairTmp : memberMap)
589  ss << ++i << ". " << memberPairTmp.first << "\n";
590  //__COUT_ERR__ << "\n" << ss.str();
591  __SS_THROW__;
592  }
593  }
594  }
595 
596  if(isContext && matchCount != contextMemberNames_.size())
597  {
598  __SS__ << "This group is an incomplete match to a Context group: "
599  << " Size=" << matchCount << " but should be "
600  << contextMemberNames_.size() << __E__;
601  __COUT_ERR__ << "\n" << ss.str();
602  ss << "\nThe members currently are...\n";
603  int i = 0;
604  for(auto& memberPair : memberMap)
605  ss << ++i << ". " << memberPair.first << "\n";
606  ss << "\nThe expected Context members are...\n";
607  i = 0;
608  for(auto& memberName : contextMemberNames_)
609  ss << ++i << ". " << memberName << "\n";
610  //__COUT_ERR__ << "\n" << ss.str();
611  __SS_THROW__;
612  }
613 
614  if(isBackbone && matchCount != backboneMemberNames_.size())
615  {
616  __SS__ << "This group is an incomplete match to a Backbone group: "
617  << " Size=" << matchCount << " but should be "
618  << backboneMemberNames_.size() << __E__;
619  __COUT_ERR__ << "\n" << ss.str();
620  ss << "\nThe members currently are...\n";
621  int i = 0;
622  for(auto& memberPair : memberMap)
623  ss << ++i << ". " << memberPair.first << "\n";
624  ss << "\nThe expected Backbone members are...\n";
625  i = 0;
626  for(auto& memberName : backboneMemberNames_)
627  ss << ++i << ". " << memberName << "\n";
628  //__COUT_ERR__ << "\n" << ss.str();
629  __SS_THROW__;
630  }
631 
632  if(isIterate && matchCount != iterateMemberNames_.size())
633  {
634  __SS__ << "This group is an incomplete match to a Iterate group: "
635  << " Size=" << matchCount << " but should be "
636  << iterateMemberNames_.size() << __E__;
637  __COUT_ERR__ << "\n" << ss.str();
638  ss << "\nThe members currently are...\n";
639  int i = 0;
640  for(auto& memberPair : memberMap)
641  ss << ++i << ". " << memberPair.first << "\n";
642  ss << "\nThe expected Iterate members are...\n";
643  i = 0;
644  for(auto& memberName : iterateMemberNames_)
645  ss << ++i << ". " << memberName << "\n";
646  //__COUT_ERR__ << "\n" << ss.str();
647  __SS_THROW__;
648  }
649 
650  return isContext ? CONTEXT_TYPE
651  : (isBackbone ? BACKBONE_TYPE
652  : (isIterate ? ITERATE_TYPE : CONFIGURATION_TYPE));
653 }
654 
655 //==============================================================================
656 // getTypeNameOfGroup
657 // return string for group type
658 const std::string& ConfigurationManager::getTypeNameOfGroup(
659  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap)
660 {
661  return convertGroupTypeIdToName(getTypeOfGroup(memberMap));
662 }
663 
664 //==============================================================================
665 // loadMemberMap
666 // loads tables given by name/version pairs in memberMap
667 // Note: does not activate them.
668 //
669 // if filePath == "", then output to cout
670 void ConfigurationManager::dumpActiveConfiguration(const std::string& filePath,
671  const std::string& dumpType)
672 {
673  time_t rawtime = time(0);
674  __COUT__ << "filePath = " << filePath << __E__;
675  __COUT__ << "dumpType = " << dumpType << __E__;
676 
677  std::ofstream fs;
678  fs.open(filePath, std::fstream::out | std::fstream::trunc);
679 
680  std::ostream* out;
681 
682  // if file was valid use it, else default to cout
683  if(fs.is_open())
684  out = &fs;
685  else
686  {
687  if(filePath != "")
688  {
689  __SS__ << "Invalid file path to dump active configuration. File " << filePath
690  << " could not be opened!" << __E__;
691  __COUT_ERR__ << ss.str();
692  __SS_THROW__;
693  }
694  out = &(std::cout);
695  }
696 
697  (*out) << "#################################" << __E__;
698  (*out) << "This is an ots configuration dump.\n\n" << __E__;
699  (*out) << "Source database is $ARTDAQ_DATABASE_URI = \t"
700  << __ENV__("ARTDAQ_DATABASE_URI") << __E__;
701  (*out) << "\nOriginal location of dump: \t" << filePath << __E__;
702  (*out) << "Type of dump: \t" << dumpType << __E__;
703  (*out) << "Linux time for dump: \t" << rawtime << __E__;
704 
705  {
706  struct tm* timeinfo = localtime(&rawtime);
707  char buffer[100];
708  strftime(buffer, 100, "%c %Z", timeinfo);
709  (*out) << "Display time for dump: \t" << buffer << __E__;
710  }
711 
712  // define local "lambda" functions
713  // active groups
714  // active tables
715  // active group members
716  // active table contents
717 
718  auto localDumpActiveGroups = [](const ConfigurationManager* cfgMgr,
719  std::ostream* out) {
720  std::map<std::string, std::pair<std::string, TableGroupKey>> activeGroups =
721  cfgMgr->getActiveTableGroups();
722 
723  (*out) << "\n\n************************" << __E__;
724  (*out) << "Active Groups:" << __E__;
725  for(auto& group : activeGroups)
726  {
727  (*out) << "\t" << group.first << " := " << group.second.first << " ("
728  << group.second.second << ")" << __E__;
729  }
730  };
731 
732  auto localDumpActiveTables = [](const ConfigurationManager* cfgMgr,
733  std::ostream* out) {
734  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
735 
736  (*out) << "\n\n************************" << __E__;
737  (*out) << "Active Tables:" << __E__;
738  (*out) << "Active Tables count = " << activeTables.size() << __E__;
739 
740  unsigned int i = 0;
741  for(auto& table : activeTables)
742  {
743  (*out) << "\t" << ++i << ". " << table.first << "-v" << table.second << __E__;
744  }
745  };
746 
747  auto localDumpActiveGroupMembers = [](ConfigurationManager* cfgMgr,
748  std::ostream* out) {
749  std::map<std::string, std::pair<std::string, TableGroupKey>> activeGroups =
750  cfgMgr->getActiveTableGroups();
751  (*out) << "\n\n************************" << __E__;
752  (*out) << "Active Group Members:" << __E__;
753  int tableCount = 0;
754  for(auto& group : activeGroups)
755  {
756  (*out) << "\t" << group.first << " := " << group.second.first << " ("
757  << group.second.second << ")" << __E__;
758 
759  if(group.second.first == "")
760  {
761  (*out) << "\t"
762  << "Empty group name. Assuming no active group." << __E__;
763  continue;
764  }
765 
766  std::map<std::string /*name*/, TableVersion /*version*/> memberMap;
767  std::map<std::string /*name*/, std::string /*alias*/> groupAliases;
768  std::string groupComment;
769  std::string groupAuthor;
770  std::string groupCreateTime;
771  time_t groupCreateTime_t;
772 
773  cfgMgr->loadTableGroup(group.second.first,
774  group.second.second,
775  false /*doActivate*/,
776  &memberMap /*memberMap*/,
777  0 /*progressBar*/,
778  0 /*accumulateErrors*/,
779  &groupComment,
780  &groupAuthor,
781  &groupCreateTime,
782  true /*doNotLoadMember*/,
783  0 /*groupTypeString*/,
784  &groupAliases);
785 
786  (*out) << "\t\tGroup Comment: \t" << groupComment << __E__;
787  (*out) << "\t\tGroup Author: \t" << groupAuthor << __E__;
788 
789  sscanf(groupCreateTime.c_str(), "%ld", &groupCreateTime_t);
790  (*out) << "\t\tGroup Create Time: \t" << ctime(&groupCreateTime_t) << __E__;
791  (*out) << "\t\tGroup Aliases: \t" << StringMacros::mapToString(groupAliases)
792  << __E__;
793 
794  (*out) << "\t\tMember table count = " << memberMap.size() << __E__;
795  tableCount += memberMap.size();
796 
797  unsigned int i = 0;
798  for(auto& member : memberMap)
799  {
800  (*out) << "\t\t\t" << ++i << ". " << member.first << "-v" << member.second
801  << __E__;
802  }
803  }
804  (*out) << "\nActive Group Members total table count = " << tableCount << __E__;
805  };
806 
807  auto localDumpActiveTableContents = [](const ConfigurationManager* cfgMgr,
808  std::ostream* out) {
809  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
810 
811  (*out) << "\n\n************************" << __E__;
812  (*out) << "Active Table Contents (table count = " << activeTables.size()
813  << "):" << __E__;
814  unsigned int i = 0;
815  for(auto& table : activeTables)
816  {
817  (*out) << "\n\n=============================================================="
818  "================"
819  << __E__;
820  (*out) << "=================================================================="
821  "============"
822  << __E__;
823  (*out) << "\t" << ++i << ". " << table.first << "-v" << table.second << __E__;
824 
825  cfgMgr->nameToTableMap_.find(table.first)->second->print(*out);
826  }
827  };
828 
829  if(dumpType == "GroupKeys")
830  {
831  localDumpActiveGroups(this, out);
832  }
833  else if(dumpType == "TableVersions")
834  {
835  localDumpActiveTables(this, out);
836  }
837  else if(dumpType == "GroupKeysAndTableVersions")
838  {
839  localDumpActiveGroups(this, out);
840  localDumpActiveTables(this, out);
841  }
842  else if(dumpType == "All")
843  {
844  localDumpActiveGroups(this, out);
845  localDumpActiveGroupMembers(this, out);
846  localDumpActiveTables(this, out);
847  localDumpActiveTableContents(this, out);
848  }
849  else
850  {
851  __SS__
852  << "Invalid dump type '" << dumpType
853  << "' given during dumpActiveConfiguration(). Valid types are as follows:\n"
854  <<
855 
856  // List all choices
857  "GroupKeys"
858  << ", "
859  << "TableVersions"
860  << ", "
861  << "GroupsKeysAndTableVersions"
862  << ", "
863  << "All"
864  <<
865 
866  "\n\nPlease change the State Machine configuration to a valid dump type."
867  << __E__;
868  __SS_THROW__;
869  }
870 
871  if(fs.is_open())
872  fs.close();
873 }
874 
875 //==============================================================================
876 // loadMemberMap
877 // loads tables given by name/version pairs in memberMap
878 // Note: does not activate them.
879 void ConfigurationManager::loadMemberMap(
880  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap,
881  std::string* accumulateWarnings /* =0 */)
882 {
883  TableBase* tmpConfigBasePtr;
884  // for each member
885  // get()
886  for(auto& memberPair : memberMap)
887  {
888  //__COUT__ << "\tMember config " << memberPair.first << ":" <<
889  // memberPair.second << __E__;
890 
891  // get the proper temporary pointer
892  // use 0 if doesn't exist yet.
893  // Note: do not want to give nameToTableMap_[memberPair.first]
894  // in case there is failure in get... (exceptions may be thrown)
895  // Note: Default constructor is called by Map, i.e.
896  // nameToTableMap_[memberPair.first] = 0; //create pointer and set to 0
897  tmpConfigBasePtr = 0;
898  if(nameToTableMap_.find(memberPair.first) != nameToTableMap_.end())
899  tmpConfigBasePtr = nameToTableMap_[memberPair.first];
900 
901  std::string getError = "";
902  try
903  {
904  theInterface_->get(tmpConfigBasePtr, // configurationPtr
905  memberPair.first, // tableName
906  0, // groupKey
907  0, // groupName
908  false, // dontFill=false to fill
909  memberPair.second, // version
910  false // resetTable
911  );
912  }
913  catch(const std::runtime_error& e)
914  {
915  __SS__ << "Failed to load member table '" << memberPair.first
916  << "' - here is the error: \n\n"
917  << e.what() << __E__;
918 
919  ss << "\nIf the table '" << memberPair.first
920  << "' should not exist, then please remove it from the group. If it "
921  "should exist, then it "
922  << "seems to be missing; use the Table Editor to create it, or copy it "
923  "from another source."
924  << __E__;
925 
926  // if accumulating warnings and table view was created, then continue
927  if(accumulateWarnings)
928  getError = ss.str();
929  else
930  __SS_THROW__;
931  }
932  catch(...)
933  {
934  __SS__ << "Failed to load member table '" << memberPair.first
935  << "' due to unknown error!" << __E__;
936 
937  ss << "\nIf the table '" << memberPair.first
938  << "' should not exist, then please remove it from the group. If it "
939  "should exist, then it "
940  << "seems to be missing; use the Table Editor to create it, or copy it "
941  "from another source."
942  << __E__;
943 
944  // if accumulating warnings and table view was created, then continue
945  if(accumulateWarnings)
946  getError = ss.str();
947  else
948  __SS_THROW__;
949  }
950 
951  if(!tmpConfigBasePtr)
952  {
953  __SS__ << "Null pointer returned for table '" << memberPair.first
954  << ".' Was the table info deleted?" << __E__;
955  __COUT_ERR__ << ss.str();
956 
957  nameToTableMap_.erase(memberPair.first);
958  if(accumulateWarnings)
959  {
960  *accumulateWarnings += ss.str();
961  continue;
962  }
963  else
964  __SS_THROW__;
965  }
966 
967  nameToTableMap_[memberPair.first] = tmpConfigBasePtr;
968  if(nameToTableMap_[memberPair.first]->getViewP())
969  {
970  //__COUT__ << "Activated version: " <<
971  // nameToTableMap_[memberPair.first]->getViewVersion() << __E__;
972 
973  if(accumulateWarnings && getError != "")
974  {
975  __SS__ << "Error caught during '" << memberPair.first
976  << "' table retrieval: \n"
977  << getError << __E__;
978  __COUT_ERR__ << ss.str();
979  *accumulateWarnings += ss.str();
980  }
981  }
982  else
983  {
984  __SS__ << nameToTableMap_[memberPair.first]->getTableName()
985  << ": View version not activated properly!";
986  __SS_THROW__;
987  }
988  }
989 } // end loadMemberMap()
990 
991 //==============================================================================
992 // loadTableGroup
993 // load all members of configuration group
994 // if doActivate
995 // DOES set theConfigurationTableGroup_, theContextTableGroup_, or
996 // theBackboneTableGroup_ on success this also happens with
997 // ConfigurationManagerRW::activateTableGroup for each member
998 // configBase->init()
999 //
1000 // if progressBar != 0, then do step handling, for finer granularity
1001 //
1002 // if(doNotLoadMember) return memberMap; //this is useful if just getting group metadata
1003 // else NOTE: active views are changed! (when loading member map)
1004 //
1005 // throws exception on failure.
1006 // map<name , TableVersion >
1007 void ConfigurationManager::loadTableGroup(
1008  const std::string& groupName,
1009  TableGroupKey groupKey,
1010  bool doActivate /*=false*/,
1011  std::map<std::string, TableVersion>* groupMembers,
1012  ProgressBar* progressBar,
1013  std::string* accumulatedTreeErrors,
1014  std::string* groupComment,
1015  std::string* groupAuthor,
1016  std::string* groupCreateTime,
1017  bool doNotLoadMember /*=false*/,
1018  std::string* groupTypeString,
1019  std::map<std::string /*name*/, std::string /*alias*/>* groupAliases,
1020  bool onlyLoadIfBackboneOrContext /*=false*/) try
1021 {
1022  // clear to defaults
1023  if(groupComment)
1024  *groupComment = "NO COMMENT FOUND";
1025  if(groupAuthor)
1026  *groupAuthor = "NO AUTHOR FOUND";
1027  if(groupCreateTime)
1028  *groupCreateTime = "0";
1029  if(groupTypeString)
1030  *groupTypeString = "UNKNOWN";
1031 
1032  // if(groupName == "defaultConfig")
1033  // { //debug active versions
1034  // std::map<std::string, TableVersion> allActivePairs = getActiveVersions();
1035  // for(auto& activePair: allActivePairs)
1036  // {
1037  // __COUT__ << "Active table = " <<
1038  // activePair.first << "-v" <<
1039  // getTableByName(activePair.first)->getView().getVersion() <<
1040  // __E__;
1041  // }
1042  // }
1043 
1044  // load all members of configuration group
1045  // if doActivate
1046  // determine the type configuration
1047  // deactivate all of that type (invalidate active view)
1048  //
1049  // for each member
1050  // get()
1051  // if doActivate, configBase->init()
1052  //
1053  // if doActivate
1054  // set theConfigurationTableGroup_, theContextTableGroup_, or
1055  // theBackboneTableGroup_ on success
1056 
1057  // __COUT_INFO__ << "Loading Table Group: " << groupName <<
1058  // "(" << groupKey << ")" << __E__;
1059 
1060  std::map<std::string /*name*/, TableVersion /*version*/> memberMap =
1061  theInterface_->getTableGroupMembers(
1062  TableGroupKey::getFullGroupString(groupName, groupKey),
1063  true /*include meta data table*/);
1064  std::map<std::string /*name*/, std::string /*alias*/> aliasMap;
1065 
1066  if(progressBar)
1067  progressBar->step();
1068 
1069  // remove meta data table and extract info
1070  auto metaTablePair = memberMap.find(groupMetadataTable_.getTableName());
1071  if(metaTablePair != memberMap.end())
1072  {
1073  //__COUT__ << "Found group meta data. v" << metaTablePair->second << __E__;
1074 
1075  memberMap.erase(metaTablePair); // remove from member map that is returned
1076 
1077  // clear table
1078  while(groupMetadataTable_.getView().getNumberOfRows())
1079  groupMetadataTable_.getViewP()->deleteRow(0);
1080 
1081  // retrieve metadata from database
1082  try
1083  {
1084  theInterface_->fill(&groupMetadataTable_, metaTablePair->second);
1085  }
1086  catch(const std::runtime_error& e)
1087  {
1088  __COUT_WARN__ << "Ignoring metadata error: " << e.what() << __E__;
1089  }
1090  catch(...)
1091  {
1092  __COUT_WARN__ << "Ignoring unknown metadata error. " << __E__;
1093  }
1094 
1095  // check that there is only 1 row
1096  if(groupMetadataTable_.getView().getNumberOfRows() != 1)
1097  {
1098  if(groupMembers)
1099  *groupMembers = memberMap; // copy for return
1100 
1101  groupMetadataTable_.print();
1102  __SS__ << "Ignoring that groupMetadataTable_ has wrong number of rows! Must "
1103  "be 1. Going with anonymous defaults."
1104  << __E__;
1105  __COUT_ERR__ << "\n" << ss.str();
1106 
1107  // fix metadata table
1108  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
1109  groupMetadataTable_.getViewP()->deleteRow(0);
1110  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
1111  groupMetadataTable_.getViewP()->addRow();
1112 
1113  if(groupComment)
1114  *groupComment = "NO COMMENT FOUND";
1115  if(groupAuthor)
1116  *groupAuthor = "NO AUTHOR FOUND";
1117  if(groupCreateTime)
1118  *groupCreateTime = "0";
1119 
1120  int groupType = -1;
1121  if(groupTypeString) // do before exit case
1122  {
1123  groupType = getTypeOfGroup(memberMap);
1124  *groupTypeString = convertGroupTypeIdToName(groupType);
1125  }
1126  return; // memberMap;
1127  }
1128 
1129  // groupMetadataTable_.print();
1130 
1131  // extract fields
1132  StringMacros::getMapFromString(groupMetadataTable_.getView().getValueAsString(
1133  0, ConfigurationManager::METADATA_COL_ALIASES),
1134  aliasMap);
1135  if(groupAliases)
1136  *groupAliases = aliasMap;
1137  if(groupComment)
1138  *groupComment = groupMetadataTable_.getView().getValueAsString(
1139  0, ConfigurationManager::METADATA_COL_COMMENT);
1140  if(groupAuthor)
1141  *groupAuthor = groupMetadataTable_.getView().getValueAsString(
1142  0, ConfigurationManager::METADATA_COL_AUTHOR);
1143  if(groupCreateTime)
1144  *groupCreateTime = groupMetadataTable_.getView().getValueAsString(
1145  0, ConfigurationManager::METADATA_COL_TIMESTAMP);
1146 
1147  // modify members based on aliases
1148  {
1149  std::map<std::string /*table*/, std::map<std::string /*alias*/, TableVersion>>
1150  versionAliases;
1151  if(aliasMap.size()) // load version aliases
1152  {
1153  __COUTV__(StringMacros::mapToString(aliasMap));
1154  versionAliases = ConfigurationManager::getVersionAliases();
1155  __COUTV__(StringMacros::mapToString(versionAliases));
1156  }
1157 
1158  // convert alias to version
1159  for(auto& aliasPair : aliasMap)
1160  {
1161  // check for alias table in member names
1162  if(memberMap.find(aliasPair.first) != memberMap.end())
1163  {
1164  __COUT__ << "Group member '" << aliasPair.first
1165  << "' was found in group member map!" << __E__;
1166  __COUT__ << "Looking for alias '" << aliasPair.second
1167  << "' in active version aliases..." << __E__;
1168 
1169  if(versionAliases.find(aliasPair.first) == versionAliases.end() ||
1170  versionAliases[aliasPair.first].find(aliasPair.second) ==
1171  versionAliases[aliasPair.first].end())
1172  {
1173  __SS__ << "Group '" << groupName << "(" << groupKey
1174  << ")' requires table version alias '" << aliasPair.first
1175  << ":" << aliasPair.second
1176  << ",' which was not found in the active Backbone!"
1177  << __E__;
1178  __SS_THROW__;
1179  }
1180 
1181  memberMap[aliasPair.first] =
1182  versionAliases[aliasPair.first][aliasPair.second];
1183  __COUT__ << "Version alias translated to " << aliasPair.first
1184  << __E__;
1185  }
1186  }
1187  }
1188  } // end metadata handling
1189 
1190  if(groupMembers)
1191  *groupMembers = memberMap; // copy map for return
1192 
1193  if(progressBar)
1194  progressBar->step();
1195 
1196  //__COUT__ << "memberMap loaded size = " << memberMap.size() << __E__;
1197 
1198  int groupType = -1;
1199  try
1200  {
1201  if(groupTypeString) // do before exit case
1202  {
1203  groupType = getTypeOfGroup(memberMap);
1204  *groupTypeString = convertGroupTypeIdToName(groupType);
1205  }
1206 
1207  // if(groupName == "defaultConfig")
1208  // { //debug active versions
1209  // std::map<std::string, TableVersion> allActivePairs =
1210  // getActiveVersions(); for(auto& activePair: allActivePairs)
1211  // {
1212  // __COUT__ << "Active table = " <<
1213  // activePair.first << "-v" <<
1214  // getTableByName(activePair.first)->getView().getVersion()
1215  //<< __E__;
1216  // }
1217  // }
1218 
1219  if(doNotLoadMember)
1220  return; // memberMap; //this is useful if just getting group metadata
1221 
1222  // if not already done, determine the type configuration group
1223  if(!groupTypeString)
1224  groupType = getTypeOfGroup(memberMap);
1225 
1226  if(onlyLoadIfBackboneOrContext &&
1227  groupType != ConfigurationManager::CONTEXT_TYPE &&
1228  groupType != ConfigurationManager::BACKBONE_TYPE)
1229  {
1230  __COUT_WARN__ << "Not loading group because it is not of type Context or "
1231  "Backbone (it is type '"
1232  << convertGroupTypeIdToName(groupType) << "')." << __E__;
1233  return;
1234  }
1235 
1236  if(doActivate)
1237  __COUT__ << "------------------------------------- init start \t [for all "
1238  "plug-ins in "
1239  << convertGroupTypeIdToName(groupType) << " group '" << groupName
1240  << "(" << groupKey << ")"
1241  << "']" << __E__;
1242 
1243  if(doActivate)
1244  {
1245  std::string groupToDeactivate =
1246  groupType == ConfigurationManager::CONTEXT_TYPE
1247  ? theContextTableGroup_
1248  : (groupType == ConfigurationManager::BACKBONE_TYPE
1249  ? theBackboneTableGroup_
1250  : (groupType == ConfigurationManager::ITERATE_TYPE
1251  ? theIterateTableGroup_
1252  : theConfigurationTableGroup_));
1253 
1254  // deactivate all of that type (invalidate active view)
1255  if(groupToDeactivate != "") // deactivate only if pre-existing group
1256  {
1257  //__COUT__ << "groupToDeactivate '" << groupToDeactivate << "'" <<
1258  // __E__;
1259  destroyTableGroup(groupToDeactivate, true);
1260  }
1261  // else
1262  // {
1263  // //Getting here, is kind of strange:
1264  // // - this group may have only been partially loaded before?
1265  // }
1266  }
1267  // if(groupName == "defaultConfig")
1268  // { //debug active versions
1269  // std::map<std::string, TableVersion> allActivePairs =
1270  // getActiveVersions(); for(auto& activePair: allActivePairs)
1271  // {
1272  // __COUT__ << "Active table = " <<
1273  // activePair.first << "-v" <<
1274  // getTableByName(activePair.first)->getView().getVersion()
1275  //<< __E__;
1276  // }
1277  // }
1278 
1279  if(progressBar)
1280  progressBar->step();
1281 
1282  //__COUT__ << "Loading member map..." << __E__;
1283 
1284  loadMemberMap(memberMap, accumulatedTreeErrors);
1285 
1286  //__COUT__ << "Member map loaded..." << __E__;
1287 
1288  if(progressBar)
1289  progressBar->step();
1290 
1291  if(accumulatedTreeErrors)
1292  {
1293  //__COUT__ << "Checking chosen group for tree errors..." << __E__;
1294 
1295  getChildren(&memberMap, accumulatedTreeErrors);
1296  if(*accumulatedTreeErrors != "")
1297  {
1298  __COUT_ERR__ << "Errors detected while loading Table Group: " << groupName
1299  << "(" << groupKey << "). Aborting."
1300  << "\n"
1301  << *accumulatedTreeErrors << __E__;
1302  return; // memberMap; //return member name map to version
1303  }
1304  }
1305 
1306  if(progressBar)
1307  progressBar->step();
1308 
1309  // for each member
1310  // if doActivate, configBase->init()
1311  if(doActivate)
1312  for(auto& memberPair : memberMap)
1313  {
1314  // do NOT allow activating Scratch versions if tracking is ON!
1315  if(ConfigurationInterface::isVersionTrackingEnabled() &&
1316  memberPair.second.isScratchVersion())
1317  {
1318  __SS__ << "Error while activating member Table '"
1319  << nameToTableMap_[memberPair.first]->getTableName() << "-v"
1320  << memberPair.second << " for Table Group '" << groupName
1321  << "(" << groupKey
1322  << ")'. When version tracking is enabled, Scratch views"
1323  << " are not allowed! Please only use unique, persistent "
1324  "versions when version tracking is enabled."
1325  << __E__;
1326  __COUT_ERR__ << "\n" << ss.str();
1327  __SS_THROW__;
1328  }
1329 
1330  //__COUTV__(memberPair.first);
1331 
1332  // attempt to init using the configuration's specific init
1333  // this could be risky user code, try and catch
1334  try
1335  {
1336  nameToTableMap_[memberPair.first]->init(this);
1337  }
1338  catch(std::runtime_error& e)
1339  {
1340  __SS__ << "Error detected calling "
1341  << nameToTableMap_[memberPair.first]->getTableName()
1342  << ".init()!\n\n " << e.what() << __E__;
1343 
1344  //__SS_THROW__;
1345 
1346  if(accumulatedTreeErrors)
1347  {
1348  *accumulatedTreeErrors += ss.str();
1349  }
1350  else
1351  __SS_THROW__; //__COUT_WARN__ << ss.str();
1352  }
1353  catch(...)
1354  {
1355  __SS__ << "Unknown Error detected calling "
1356  << nameToTableMap_[memberPair.first]->getTableName()
1357  << ".init()!\n\n " << __E__;
1358  //__SS_THROW__;
1359  if(accumulatedTreeErrors)
1360  {
1361  *accumulatedTreeErrors += ss.str();
1362  }
1363  else // ignore error
1364  __COUT_WARN__ << ss.str();
1365  }
1366  }
1367 
1368  if(progressBar)
1369  progressBar->step();
1370 
1371  // if doActivate
1372  // set theConfigurationTableGroup_, theContextTableGroup_, or
1373  // theBackboneTableGroup_ on
1374  // success
1375 
1376  if(doActivate)
1377  {
1378  if(groupType == ConfigurationManager::CONTEXT_TYPE) //
1379  {
1380  // __COUT_INFO__ << "Type=Context, Group loaded: " <<
1381  // groupName
1382  //<<
1383  // "(" << groupKey << ")" << __E__;
1384  theContextTableGroup_ = groupName;
1385  theContextTableGroupKey_ =
1386  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
1387  }
1388  else if(groupType == ConfigurationManager::BACKBONE_TYPE)
1389  {
1390  // __COUT_INFO__ << "Type=Backbone, Group loaded: " <<
1391  // groupName <<
1392  // "(" << groupKey << ")" << __E__;
1393  theBackboneTableGroup_ = groupName;
1394  theBackboneTableGroupKey_ =
1395  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
1396  }
1397  else if(groupType == ConfigurationManager::ITERATE_TYPE)
1398  {
1399  // __COUT_INFO__ << "Type=Iterate, Group loaded: " <<
1400  // groupName
1401  //<<
1402  // "(" << groupKey << ")" << __E__;
1403  theIterateTableGroup_ = groupName;
1404  theIterateTableGroupKey_ =
1405  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
1406  }
1407  else // is theConfigurationTableGroup_
1408  {
1409  // __COUT_INFO__ << "Type=Configuration, Group loaded: " <<
1410  // groupName <<
1411  // "(" << groupKey << ")" << __E__;
1412  theConfigurationTableGroup_ = groupName;
1413  theConfigurationTableGroupKey_ =
1414  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
1415  }
1416  }
1417 
1418  if(progressBar)
1419  progressBar->step();
1420 
1421  if(doActivate)
1422  __COUT__ << "------------------------------------- init complete \t [for all "
1423  "plug-ins in "
1424  << convertGroupTypeIdToName(groupType) << " group '" << groupName
1425  << "(" << groupKey << ")"
1426  << "']" << __E__;
1427  } // end failed group load try
1428  catch(...)
1429  {
1430  // save group name and key of failed load attempt
1431  lastFailedGroupLoad_[convertGroupTypeIdToName(groupType)] =
1432  std::pair<std::string, TableGroupKey>(groupName, TableGroupKey(groupKey));
1433 
1434  try
1435  {
1436  throw;
1437  }
1438  catch(const std::runtime_error& e)
1439  {
1440  __SS__ << "Error occurred while loading table group '" << groupName << "("
1441  << groupKey << ")': \n"
1442  << e.what() << __E__;
1443  __COUT_WARN__ << ss.str();
1444  if(accumulatedTreeErrors)
1445  *accumulatedTreeErrors += ss.str();
1446  else
1447  __SS_THROW__;
1448  }
1449  catch(...)
1450  {
1451  __SS__ << "An unknown error occurred while loading table group '" << groupName
1452  << "(" << groupKey << ")." << __E__;
1453  __COUT_WARN__ << ss.str();
1454  if(accumulatedTreeErrors)
1455  *accumulatedTreeErrors += ss.str();
1456  else
1457  __SS_THROW__;
1458  }
1459  }
1460 
1461  return;
1462 }
1463 catch(...)
1464 {
1465  // save group name and key of failed load attempt
1466  lastFailedGroupLoad_[ConfigurationManager::ACTIVE_GROUP_NAME_UNKNOWN] =
1467  std::pair<std::string, TableGroupKey>(groupName, TableGroupKey(groupKey));
1468 
1469  try
1470  {
1471  throw;
1472  }
1473  catch(const std::runtime_error& e)
1474  {
1475  __SS__ << "Error occurred while loading table group: " << e.what() << __E__;
1476  __COUT_WARN__ << ss.str();
1477  if(accumulatedTreeErrors)
1478  *accumulatedTreeErrors += ss.str();
1479  else
1480  __SS_THROW__;
1481  }
1482  catch(...)
1483  {
1484  __SS__ << "An unknown error occurred while loading table group." << __E__;
1485  __COUT_WARN__ << ss.str();
1486  if(accumulatedTreeErrors)
1487  *accumulatedTreeErrors += ss.str();
1488  else
1489  __SS_THROW__;
1490  }
1491 } // end loadTableGroup()
1492 
1493 //==============================================================================
1494 // getActiveTableGroups
1495 // get the active table groups map
1496 // map<type, pair <groupName , TableGroupKey> >
1497 //
1498 // Note: invalid TableGroupKey means no active group currently
1499 std::map<std::string, std::pair<std::string, TableGroupKey>>
1500 ConfigurationManager::getActiveTableGroups(void) const
1501 {
1502  // map<type, pair <groupName , TableGroupKey> >
1503  std::map<std::string, std::pair<std::string, TableGroupKey>> retMap;
1504 
1505  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT] =
1506  std::pair<std::string, TableGroupKey>(
1507  theContextTableGroup_,
1508  theContextTableGroupKey_ ? *theContextTableGroupKey_ : TableGroupKey());
1509  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE] =
1510  std::pair<std::string, TableGroupKey>(
1511  theBackboneTableGroup_,
1512  theBackboneTableGroupKey_ ? *theBackboneTableGroupKey_ : TableGroupKey());
1513  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE] =
1514  std::pair<std::string, TableGroupKey>(
1515  theIterateTableGroup_,
1516  theIterateTableGroupKey_ ? *theIterateTableGroupKey_ : TableGroupKey());
1517  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION] =
1518  std::pair<std::string, TableGroupKey>(theConfigurationTableGroup_,
1519  theConfigurationTableGroupKey_
1520  ? *theConfigurationTableGroupKey_
1521  : TableGroupKey());
1522  return retMap;
1523 } // end getActiveTableGroups()
1524 
1525 //==============================================================================
1526 const std::string& ConfigurationManager::getActiveGroupName(const std::string& type) const
1527 {
1528  if(type == "" || type == ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
1529  return theConfigurationTableGroup_;
1530  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
1531  return theContextTableGroup_;
1532  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
1533  return theBackboneTableGroup_;
1534  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
1535  return theIterateTableGroup_;
1536 
1537  __SS__ << "Invalid type requested '" << type << "'" << __E__;
1538  __COUT_ERR__ << ss.str();
1539  __SS_THROW__;
1540 }
1541 
1542 //==============================================================================
1543 TableGroupKey ConfigurationManager::getActiveGroupKey(const std::string& type) const
1544 {
1545  if(type == "" || type == ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
1546  return theConfigurationTableGroupKey_ ? *theConfigurationTableGroupKey_
1547  : TableGroupKey();
1548  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
1549  return theContextTableGroupKey_ ? *theContextTableGroupKey_ : TableGroupKey();
1550  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
1551  return theBackboneTableGroupKey_ ? *theBackboneTableGroupKey_ : TableGroupKey();
1552  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
1553  return theIterateTableGroupKey_ ? *theIterateTableGroupKey_ : TableGroupKey();
1554 
1555  __SS__ << "Invalid type requested '" << type << "'" << __E__;
1556  __COUT_ERR__ << ss.str();
1557  __SS_THROW__;
1558 }
1559 
1560 //==============================================================================
1561 ConfigurationTree ConfigurationManager::getContextNode(
1562  const std::string& contextUID, const std::string& applicationUID) const
1563 {
1564  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
1565  contextUID);
1566 }
1567 
1568 //==============================================================================
1569 ConfigurationTree ConfigurationManager::getSupervisorNode(
1570  const std::string& contextUID, const std::string& applicationUID) const
1571 {
1572  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
1573  contextUID + "/LinkToApplicationTable/" + applicationUID);
1574 }
1575 
1576 //==============================================================================
1577 ConfigurationTree ConfigurationManager::getSupervisorTableNode(
1578  const std::string& contextUID, const std::string& applicationUID) const
1579 {
1580  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
1581  contextUID + "/LinkToApplicationTable/" + applicationUID +
1582  "/LinkToSupervisorTable");
1583 }
1584 
1585 //==============================================================================
1586 ConfigurationTree ConfigurationManager::getNode(const std::string& nodeString,
1587  bool doNotThrowOnBrokenUIDLinks) const
1588 {
1589  //__COUT__ << "nodeString=" << nodeString << " " << nodeString.length() << __E__;
1590 
1591  // get nodeName (in case of / syntax)
1592  if(nodeString.length() < 1)
1593  {
1594  __SS__ << ("Invalid empty node name") << __E__;
1595  __COUT_ERR__ << ss.str();
1596  __SS_THROW__;
1597  }
1598 
1599  // ignore multiple starting slashes
1600  unsigned int startingIndex = 0;
1601  while(startingIndex < nodeString.length() && nodeString[startingIndex] == '/')
1602  ++startingIndex;
1603 
1604  std::string nodeName = nodeString.substr(
1605  startingIndex, nodeString.find('/', startingIndex) - startingIndex);
1606  //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << __E__;
1607  if(nodeName.length() < 1)
1608  {
1609  // return root node
1610  return ConfigurationTree(this, 0);
1611 
1612  // __SS__ << "Invalid node name: " << nodeName << __E__;
1613  // __COUT_ERR__ << ss.str();
1614  // __SS_THROW__;
1615  }
1616 
1617  std::string childPath = nodeString.substr(nodeName.length() + startingIndex);
1618 
1619  //__COUT__ << "childPath=" << childPath << " " << childPath.length() << __E__;
1620 
1621  ConfigurationTree configTree(this, getTableByName(nodeName));
1622 
1623  if(childPath.length() > 1)
1624  return configTree.getNode(childPath, doNotThrowOnBrokenUIDLinks);
1625  else
1626  return configTree;
1627 }
1628 
1629 //==============================================================================
1630 // getFirstPathToNode
1631 std::string ConfigurationManager::getFirstPathToNode(const ConfigurationTree& node,
1632  const std::string& startPath) const
1633 // void ConfigurationManager::getFirstPathToNode(const ConfigurationTree &node, const
1634 // ConfigurationTree &startNode) const
1635 {
1636  std::string path = "/";
1637  return path;
1638 }
1639 
1640 //==============================================================================
1641 // getChildren
1642 // if memberMap is passed then only consider children in the map
1643 //
1644 // if accumulatedTreeErrors is non null, check for disconnects occurs.
1645 // check is 2 levels deep which should get to the links starting at tables.
1646 std::vector<std::pair<std::string, ConfigurationTree>> ConfigurationManager::getChildren(
1647  std::map<std::string, TableVersion>* memberMap,
1648  std::string* accumulatedTreeErrors) const
1649 {
1650  std::vector<std::pair<std::string, ConfigurationTree>> retMap;
1651 
1652  // if(accumulatedTreeErrors)
1653  // *accumulatedTreeErrors = "";
1654 
1655  if(!memberMap || memberMap->empty()) // return all present active members
1656  {
1657  for(auto& configPair : nameToTableMap_)
1658  {
1659  //__COUT__ << configPair.first << " " << (int)(configPair.second?1:0) <<
1660  // __E__;
1661 
1662  if(configPair.second->isActive()) // only consider if active
1663  {
1664  ConfigurationTree newNode(this, configPair.second);
1665 
1666  if(accumulatedTreeErrors) // check for disconnects
1667  {
1668  try
1669  {
1670  std::vector<std::pair<std::string, ConfigurationTree>>
1671  newNodeChildren = newNode.getChildren();
1672  for(auto& newNodeChild : newNodeChildren)
1673  {
1674  std::vector<std::pair<std::string, ConfigurationTree>>
1675  twoDeepChildren = newNodeChild.second.getChildren();
1676 
1677  for(auto& twoDeepChild : twoDeepChildren)
1678  {
1679  //__COUT__ << configPair.first << " " <<
1680  // newNodeChild.first << " " << twoDeepChild.first
1681  // << __E__;
1682  if(twoDeepChild.second.isLinkNode() &&
1683  twoDeepChild.second.isDisconnected() &&
1684  twoDeepChild.second.getDisconnectedTableName() !=
1685  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
1686  *accumulatedTreeErrors +=
1687  "\n\nAt node '" + configPair.first +
1688  "' with entry UID '" + newNodeChild.first +
1689  "' there is a disconnected child node at link "
1690  "column '" +
1691  twoDeepChild.first + "'" +
1692  " that points to table named '" +
1693  twoDeepChild.second.getDisconnectedTableName() +
1694  "' ...";
1695  }
1696  }
1697  }
1698  catch(std::runtime_error& e)
1699  {
1700  *accumulatedTreeErrors +=
1701  "\n\nAt node '" + configPair.first +
1702  "' error detected descending through children:\n" + e.what();
1703  }
1704  }
1705 
1706  retMap.push_back(
1707  std::pair<std::string, ConfigurationTree>(configPair.first, newNode));
1708  }
1709 
1710  //__COUT__ << configPair.first << __E__;
1711  }
1712  }
1713  else // return only members from the member map (they must be present and active!)
1714  {
1715  for(auto& memberPair : *memberMap)
1716  {
1717  auto mapIt = nameToTableMap_.find(memberPair.first);
1718  if(mapIt == nameToTableMap_.end())
1719  {
1720  __SS__ << "Get Children with member map requires a child '"
1721  << memberPair.first << "' that is not present!" << __E__;
1722  __SS_THROW__;
1723  }
1724  if(!(*mapIt).second->isActive())
1725  {
1726  __SS__ << "Get Children with member map requires a child '"
1727  << memberPair.first << "' that is not active!" << __E__;
1728  __SS_THROW__;
1729  }
1730 
1731  ConfigurationTree newNode(this, (*mapIt).second);
1732 
1733  if(accumulatedTreeErrors) // check for disconnects
1734  {
1735  try
1736  {
1737  std::vector<std::pair<std::string, ConfigurationTree>>
1738  newNodeChildren = newNode.getChildren();
1739  for(auto& newNodeChild : newNodeChildren)
1740  {
1741  std::vector<std::pair<std::string, ConfigurationTree>>
1742  twoDeepChildren = newNodeChild.second.getChildren();
1743 
1744  for(auto& twoDeepChild : twoDeepChildren)
1745  {
1746  //__COUT__ << memberPair.first << " " << newNodeChild.first <<
1747  //" " << twoDeepChild.first << __E__;
1748  if(twoDeepChild.second.isLinkNode() &&
1749  twoDeepChild.second.isDisconnected() &&
1750  twoDeepChild.second.getDisconnectedTableName() !=
1751  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
1752  {
1753  *accumulatedTreeErrors +=
1754  "\n\nAt node '" + memberPair.first +
1755  "' with entry UID '" + newNodeChild.first +
1756  "' there is a disconnected child node at link column "
1757  "'" +
1758  twoDeepChild.first + "'" +
1759  " that points to table named '" +
1760  twoDeepChild.second.getDisconnectedTableName() +
1761  "' ...";
1762 
1763  // check if disconnected table is in group, if not
1764  // software error
1765 
1766  bool found = false;
1767  for(auto& searchMemberPair : *memberMap)
1768  if(searchMemberPair.first ==
1769  twoDeepChild.second.getDisconnectedTableName())
1770  {
1771  found = true;
1772  break;
1773  }
1774  if(!found)
1775  {
1776  __SS__
1777  << "Note: It may be safe to ignore this "
1778  << "error since the link's target table "
1779  << twoDeepChild.second.getDisconnectedTableName()
1780  << " is not a member of this group (and may not "
1781  "be "
1782  << "loaded yet)" << __E__;
1783  *accumulatedTreeErrors += ss.str();
1784  }
1785  }
1786  }
1787  }
1788  }
1789  catch(std::runtime_error& e)
1790  {
1791  __SS__ << "At node '" << memberPair.first
1792  << "' error detected descending through children:\n"
1793  << e.what() << __E__;
1794  *accumulatedTreeErrors += ss.str();
1795  }
1796  }
1797 
1798  retMap.push_back(
1799  std::pair<std::string, ConfigurationTree>(memberPair.first, newNode));
1800  }
1801  }
1802 
1803  return retMap;
1804 } // end getChildren()
1805 
1806 //==============================================================================
1807 // getTableByName
1808 // Get read-only pointer to configuration.
1809 // If Read/Write access is needed use ConfigurationManagerWithWriteAccess
1810 // (For general use, Write access should be avoided)
1811 const TableBase* ConfigurationManager::getTableByName(const std::string& tableName) const
1812 {
1813  std::map<std::string, TableBase*>::const_iterator it;
1814  if((it = nameToTableMap_.find(tableName)) == nameToTableMap_.end())
1815  {
1816  __SS__ << "\n\nCan not find configuration named '" << tableName
1817  << "'\n\n\n\nYou need to load the configuration before it can be used."
1818  << " It probably is missing from the member list of the Table "
1819  "Group that was loaded.\n"
1820  << "\nYou may need to enter wiz mode to remedy the situation, use the "
1821  "following:\n"
1822  << "\n\t StartOTS.sh --wiz"
1823  << "\n\n\n\n"
1824  << __E__;
1825 
1826  ss << __E__ << StringMacros::stackTrace() << __E__;
1827 
1828  // prints out too often, so only throw
1829  // if(tableName != TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
1830  // __COUT_WARN__ << "\n" << ss.str();
1831  __SS_ONLY_THROW__;
1832  }
1833  return it->second;
1834 }
1835 
1836 //==============================================================================
1837 // loadConfigurationBackbone
1838 // loads the active backbone configuration group
1839 // returns the active group key that was loaded
1840 TableGroupKey ConfigurationManager::loadConfigurationBackbone()
1841 {
1842  if(!theBackboneTableGroupKey_) // no active backbone
1843  {
1844  __COUT_WARN__ << "getTableGroupKey() Failed! No active backbone currently."
1845  << __E__;
1846  return TableGroupKey();
1847  }
1848 
1849  // may already be loaded, but that's ok, load anyway to be sure
1850  loadTableGroup(theBackboneTableGroup_, *theBackboneTableGroupKey_);
1851 
1852  return *theBackboneTableGroupKey_;
1853 }
1854 
1855 // Getters
1856 //==============================================================================
1857 // getTableGroupKey
1858 // use backbone to determine default key for systemAlias.
1859 // - runType translates to group key alias,
1860 // which maps to a group name and key pair
1861 //
1862 // NOTE: temporary special aliases are also allowed
1863 // with the following format:
1864 // GROUP:<name>:<key>
1865 //
1866 // return INVALID on failure
1867 // else, pair<group name , TableGroupKey>
1868 std::pair<std::string, TableGroupKey> ConfigurationManager::getTableGroupFromAlias(
1869  std::string systemAlias, ProgressBar* progressBar)
1870 {
1871  // steps
1872  // check if special alias
1873  // if so, parse and return name/key
1874  // else, load active backbone
1875  // find runType in Group Aliases table
1876  // return key
1877 
1878  if(progressBar)
1879  progressBar->step();
1880 
1881  if(systemAlias.find("GROUP:") == 0)
1882  {
1883  if(progressBar)
1884  progressBar->step();
1885 
1886  unsigned int i = strlen("GROUP:");
1887  unsigned int j = systemAlias.find(':', i);
1888 
1889  if(progressBar)
1890  progressBar->step();
1891  if(j > i) // success
1892  return std::pair<std::string, TableGroupKey>(
1893  systemAlias.substr(i, j - i), TableGroupKey(systemAlias.substr(j + 1)));
1894  else // failure
1895  return std::pair<std::string, TableGroupKey>("", TableGroupKey());
1896  }
1897 
1898  loadConfigurationBackbone();
1899 
1900  if(progressBar)
1901  progressBar->step();
1902 
1903  try
1904  {
1905  // find runType in Group Aliases table
1906  ConfigurationTree entry =
1907  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getNode(systemAlias);
1908 
1909  if(progressBar)
1910  progressBar->step();
1911 
1912  return std::pair<std::string, TableGroupKey>(
1913  entry.getNode("GroupName").getValueAsString(),
1914  TableGroupKey(entry.getNode("GroupKey").getValueAsString()));
1915  }
1916  catch(...)
1917  {
1918  }
1919 
1920  // on failure, here
1921 
1922  if(progressBar)
1923  progressBar->step();
1924 
1925  return std::pair<std::string, TableGroupKey>("", TableGroupKey());
1926 }
1927 
1928 //==============================================================================
1929 std::map<std::string /*groupAlias*/, std::pair<std::string /*groupName*/, TableGroupKey>>
1930 ConfigurationManager::getActiveGroupAliases(void)
1931 {
1932  restoreActiveTableGroups(); // make sure the active configuration backbone is
1933  // loaded!
1934  // loadConfigurationBackbone();
1935 
1936  std::map<std::string /*groupAlias*/,
1937  std::pair<std::string /*groupName*/, TableGroupKey>>
1938  retMap;
1939 
1940  std::vector<std::pair<std::string, ConfigurationTree>> entries =
1941  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getChildren();
1942  for(auto& entryPair : entries)
1943  {
1944  retMap[entryPair.first] = std::pair<std::string, TableGroupKey>(
1945  entryPair.second.getNode("GroupName").getValueAsString(),
1946  TableGroupKey(entryPair.second.getNode("GroupKey").getValueAsString()));
1947  }
1948  return retMap;
1949 }
1950 
1951 //==============================================================================
1952 // getVersionAliases()
1953 // get version aliases organized by table, for currently active backbone tables
1954 std::map<std::string /*table name*/,
1955  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1956 ConfigurationManager::getVersionAliases(void) const
1957 {
1958  //__COUT__ << "getVersionAliases()" << __E__;
1959 
1960  std::map<std::string /*table name*/,
1961  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1962  retMap;
1963 
1964  std::map<std::string, TableVersion> activeVersions = getActiveVersions();
1965  std::string versionAliasesTableName =
1966  ConfigurationManager::VERSION_ALIASES_TABLE_NAME;
1967  if(activeVersions.find(versionAliasesTableName) == activeVersions.end())
1968  {
1969  __SS__ << "Active version of VersionAliases missing!"
1970  << "Make sure you have a valid active Backbone Group." << __E__;
1971  __COUT_WARN__ << "\n" << ss.str();
1972  return retMap;
1973  }
1974 
1975  __COUT__ << "activeVersions[\"" << versionAliasesTableName
1976  << "\"]=" << activeVersions[versionAliasesTableName] << __E__;
1977 
1978  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
1979  getNode(versionAliasesTableName).getChildren();
1980 
1981  // create map
1982  // add the first of each tableName, versionAlias pair encountered
1983  // ignore any repeats (Note: this also prevents overwriting of Scratch alias)
1984  std::string tableName, versionAlias;
1985  for(auto& aliasNodePair : aliasNodePairs)
1986  {
1987  tableName = aliasNodePair.second.getNode("TableName").getValueAsString();
1988  versionAlias = aliasNodePair.second.getNode("VersionAlias").getValueAsString();
1989 
1990  if(retMap.find(tableName) != retMap.end() &&
1991  retMap[tableName].find(versionAlias) != retMap[tableName].end())
1992  continue; // skip repeats (Note: this also prevents overwriting of Scratch
1993  // alias)
1994 
1995  // else add version to map
1996  retMap[tableName][versionAlias] =
1997  TableVersion(aliasNodePair.second.getNode("Version").getValueAsString());
1998  }
1999 
2000  return retMap;
2001 } // end getVersionAliases()
2002 
2003 //==============================================================================
2004 // getActiveVersions
2005 std::map<std::string, TableVersion> ConfigurationManager::getActiveVersions(void) const
2006 {
2007  std::map<std::string, TableVersion> retMap;
2008  for(auto& config : nameToTableMap_)
2009  {
2010  //__COUT__ << config.first << __E__;
2011 
2012  // check configuration pointer is not null and that there is an active view
2013  if(config.second && config.second->isActive())
2014  {
2015  //__COUT__ << config.first << "_v" << config.second->getViewVersion() <<
2016  // __E__;
2017  retMap.insert(std::pair<std::string, TableVersion>(
2018  config.first, config.second->getViewVersion()));
2019  }
2020  }
2021  return retMap;
2022 }
2023 
2025 // const DACStream& ConfigurationManager::getDACStream(std::string fecName)
2026 //{
2027 //
2028 // //fixme/todo this is called before setupAll so it breaks!
2029 // //====================================================
2030 // const DetectorConfiguration* detectorConfiguration =
2031 //__GET_CONFIG__(DetectorConfiguration); for(auto& type :
2032 // detectorConfiguration->getDetectorTypes()) theDACsConfigurations_[type] =
2033 //(DACsTableBase*)(getTableByName(type + "DACsConfiguration"));
2034 // //====================================================
2035 //
2036 // theDACStreams_[fecName].makeStream(fecName,
2037 // __GET_CONFIG__(DetectorConfiguration),
2038 // __GET_CONFIG__(DetectorToFEConfiguration),
2039 // theDACsConfigurations_,
2040 // __GET_CONFIG__(MaskConfiguration));//, theTrimConfiguration_);
2041 //
2042 // __COUT__ << "Done with DAC stream!" << __E__;
2043 // return theDACStreams_[fecName];
2044 //}
2045 
2046 //==============================================================================
2047 std::shared_ptr<TableGroupKey> ConfigurationManager::makeTheTableGroupKey(
2048  TableGroupKey key)
2049 {
2050  if(theConfigurationTableGroupKey_)
2051  {
2052  if(*theConfigurationTableGroupKey_ != key)
2053  destroyTableGroup();
2054  else
2055  return theConfigurationTableGroupKey_;
2056  }
2057  return std::shared_ptr<TableGroupKey>(new TableGroupKey(key));
2058 }
2059 
2060 //==============================================================================
2061 std::string ConfigurationManager::encodeURIComponent(const std::string& sourceStr)
2062 {
2063  std::string retStr = "";
2064  char encodeStr[4];
2065  for(const auto& c : sourceStr)
2066  if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
2067  retStr += c;
2068  else
2069  {
2070  sprintf(encodeStr, "%%%2.2X", c);
2071  retStr += encodeStr;
2072  }
2073  return retStr;
2074 }
2075 
2076 //==============================================================================
2077 const std::set<std::string>& ConfigurationManager::getContextMemberNames()
2078 {
2079  return ConfigurationManager::contextMemberNames_;
2080 }
2081 //==============================================================================
2082 const std::set<std::string>& ConfigurationManager::getBackboneMemberNames()
2083 {
2084  return ConfigurationManager::backboneMemberNames_;
2085 }
2086 //==============================================================================
2087 const std::set<std::string>& ConfigurationManager::getIterateMemberNames()
2088 {
2089  return ConfigurationManager::iterateMemberNames_;
2090 }
2091 
2092 //==============================================================================
2093 void ConfigurationManager::initializeFromFhicl(const std::string& fhiclPath)
2094 {
2095  __COUT__ << "Initializing from fhicl: " << fhiclPath << __E__;
2096 
2097  // https://cdcvs.fnal.gov/redmine/projects/fhicl-cpp/wiki
2098 
2099  // LoadParameterSet() ... from $ARTDAQ_INC/artdaq/Application/LoadParameterSet.hh
2100  fhicl::ParameterSet pset = LoadParameterSet(fhiclPath);
2101 
2102  //===========================
2103  // fcl should be FE record(s):
2104  // interface0: {
2105  // FEInterfacePluginName: "FEOtsUDPTemplateInterface"
2106  // LinkToFETypeTable_FEOtsUDPTemplateInterfaceTable: {
2107  // OtsInterface0: {
2108  // InterfaceIPAddress: "127.0.0.1"
2109  // InterfacePort: 4000
2110  // HostIPAddress: "127.0.0.1"
2111  // HostPort: 4020
2112  // StreamToIPAddress: "127.0.0.1"
2113  // StreamToPort: 4021
2114  // }
2115  // } //end FEOtsUDPTemplateInterfaceTable link record
2116  // } //end interface0
2117  //===========================
2118 
2119  // Steps:
2120  // Create one context with one FE supervisor
2121  // and one/many FEs specified by fcl
2122  //
2123 
2124  TableBase* table;
2125 
2126  // create context and add context record
2127  {
2128  table = 0;
2129  theInterface_->get(table, // configurationPtr
2130  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME, // tableName
2131  0, // groupKey
2132  0, // groupName
2133  true // dontFill=false to fill
2134  );
2135 
2136  nameToTableMap_[ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME] = table;
2137 
2138  table->setupMockupView(TableVersion(TableVersion::DEFAULT));
2139  table->setActiveView(TableVersion(TableVersion::DEFAULT));
2140 
2141  TableView* view = table->getViewP();
2142  __COUT__ << "Activated version: " << view->getVersion() << __E__;
2143  // view->print();
2144 
2145  // add context record ---------------------
2146  view->addRow();
2147  auto colMap = view->getColumnNamesMap();
2148 
2149  view->setValue("MacroMakerFEContext", 0, colMap["ContextUID"]);
2150  view->setValue("XDAQApplicationTable", 0, colMap["LinkToApplicationTable"]);
2151  view->setValue("MacroMakerFEContextApps", 0, colMap["ApplicationGroupID"]);
2152  view->setValue("1", 0, colMap["Status"]);
2153 
2154  __COUT__ << "Done adding context record..." << __E__;
2155  view->print();
2156 
2157  } // done with context record
2158 
2159  // create app table and add application record
2160  {
2161  table = 0;
2162  theInterface_->get(
2163  table, // configurationPtr
2164  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME, // tableName
2165  0, // groupKey
2166  0, // groupName
2167  true // dontFill=false to fill
2168  );
2169 
2170  nameToTableMap_[ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME] = table;
2171 
2172  table->setupMockupView(TableVersion(TableVersion::DEFAULT));
2173  table->setActiveView(TableVersion(TableVersion::DEFAULT));
2174 
2175  TableView* view = table->getViewP();
2176  __COUT__ << "Activated version: " << view->getVersion() << __E__;
2177  // view->print();
2178 
2179  // add application record ---------------------
2180  view->addRow();
2181  auto colMap = view->getColumnNamesMap();
2182 
2183  view->setValue("MacroMakerFEContextApps", 0, colMap["ApplicationGroupID"]);
2184  view->setValue("MacroMakerFESupervisor", 0, colMap["ApplicationUID"]);
2185  view->setValue("FESupervisorTable", 0, colMap["LinkToSupervisorTable"]);
2186  view->setValue("MacroMakerFESupervisor", 0, colMap["LinkToSupervisorUID"]);
2187  view->setValue("1", 0, colMap["Status"]);
2188 
2189  __COUT__ << "Done adding application record..." << __E__;
2190  view->print();
2191  } // done with app record
2192 
2193  // create FE Supervisor table and Supervisor record
2194  {
2195  table = 0;
2196  theInterface_->get(table, // configurationPtr
2197  "FESupervisorTable", // tableName
2198  0, // groupKey
2199  0, // groupName
2200  true // dontFill=false to fill
2201  );
2202 
2203  nameToTableMap_["FESupervisorTable"] = table;
2204 
2205  table->setupMockupView(TableVersion(TableVersion::DEFAULT));
2206  table->setActiveView(TableVersion(TableVersion::DEFAULT));
2207 
2208  TableView* view = table->getViewP();
2209  __COUT__ << "Activated version: " << view->getVersion() << __E__;
2210  // view->print();
2211 
2212  // add application record ---------------------
2213  view->addRow();
2214  auto colMap = view->getColumnNamesMap();
2215 
2216  view->setValue("MacroMakerFESupervisor", 0, colMap["SupervisorUID"]);
2217  view->setValue("FEInterfaceTable", 0, colMap["LinkToFEInterfaceTable"]);
2218  view->setValue(
2219  "MacroMakerFESupervisorInterfaces", 0, colMap["LinkToFEInterfaceGroupID"]);
2220 
2221  __COUT__ << "Done adding supervisor record..." << __E__;
2222  view->print();
2223  } // done with app record
2224 
2225  // create FE Interface table and interface record(s)
2226  recursiveInitFromFhiclPSet("FEInterfaceTable" /*tableName*/,
2227  pset /*fhicl parameter set*/,
2228  "" /*uid*/,
2229  "MacroMakerFESupervisorInterfaces" /*groupID*/,
2230  "FE" /*childLinkIndex*/);
2231 
2232  // init every table after modifications
2233  for(auto& table : nameToTableMap_)
2234  {
2235  table.second->getViewP()->init();
2236  }
2237 
2238  // verify extraction
2239  if(0)
2240  {
2241  __COUT__ << "================================================" << __E__;
2242  nameToTableMap_["FESupervisorTable"]->getViewP()->print();
2243  nameToTableMap_["FEInterfaceTable"]->getViewP()->print();
2244 
2245  auto sups = getNode("FESupervisorTable").getChildrenNames();
2246  __COUT__ << "Supervisors extracted from fhicl: " << sups.size() << __E__;
2247  auto fes = getNode("FEInterfaceTable").getChildrenNames();
2248  __COUT__ << "Front-ends extracted from fhicl: " << fes.size() << __E__;
2249  {
2250  auto a = getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
2251  __COUTV__(a.getValueAsString());
2252 
2253  auto b = a.getNode("MacroMakerFEContext");
2254  __COUTV__(b.getValueAsString());
2255 
2256  auto c = b.getNode("LinkToApplicationTable");
2257  __COUTV__(c.getValueAsString());
2258 
2259  auto d = c.getNode("MacroMakerFESupervisor");
2260  __COUTV__(d.getValueAsString());
2261 
2262  auto e = d.getNode("LinkToSupervisorTable");
2263  __COUTV__(e.getValueAsString());
2264 
2265  auto f = e.getNode("LinkToFEInterfaceTable");
2266  __COUTV__(f.getValueAsString());
2267 
2268  auto z = f.getChildrenNames();
2269  __COUTV__(StringMacros::vectorToString(z));
2270  __COUTV__(z.size());
2271  auto y = f.getChildrenNames(false /*byPriority*/, true /*onlyStatusTrue*/);
2272  __COUTV__(StringMacros::vectorToString(y));
2273  __COUTV__(y.size());
2274  auto x = f.getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/);
2275  __COUTV__(StringMacros::vectorToString(x));
2276  __COUTV__(x.size());
2277 
2278  auto g = f.getNode("dtc0");
2279  __COUTV__(g.getValueAsString());
2280  auto h = f.getNode("interface0");
2281  __COUTV__(h.getValueAsString());
2282 
2283  auto fes =
2284  getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME)
2285  .getNode(
2286  "MacroMakerFEContext/LinkToApplicationTable/"
2287  "MacroMakerFESupervisor/LinkToSupervisorTable")
2288  .getNode("LinkToFEInterfaceTable")
2289  .getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/);
2290  __COUTV__(fes.size());
2291  __COUTV__(StringMacros::vectorToString(fes));
2292  }
2293  }
2294 
2295 } // end initializeFromFhicl()
2296 
2297 //==============================================================================
2298 // recursiveInitFromFhiclPSet
2299 // Add records and all children parameters starting at table
2300 // recursively. If groupName given then loop through
2301 // records and add to table.
2302 void ConfigurationManager::recursiveInitFromFhiclPSet(const std::string& tableName,
2303  const fhicl::ParameterSet& pset,
2304  const std::string& recordName,
2305  const std::string& groupName,
2306  const std::string& groupLinkIndex)
2307 {
2308  __COUT__ << __COUT_HDR_P__ << "Adding table '" << tableName << "' record(s)..."
2309  << __E__;
2310 
2311  TableBase* table;
2312  // create context and add context record
2313  {
2314  table = 0;
2315  if(nameToTableMap_.find(tableName) == nameToTableMap_.end())
2316  {
2317  __COUT__ << "Table not found, so making '" << tableName << "'instance..."
2318  << __E__;
2319  theInterface_->get(table, // configurationPtr
2320  tableName, // tableName
2321  0, // groupKey
2322  0, // groupName
2323  true // dontFill=false to fill
2324  );
2325 
2326  nameToTableMap_[tableName] = table;
2327  table->setupMockupView(TableVersion(TableVersion::DEFAULT));
2328  }
2329  else
2330  {
2331  __COUT__ << "Existing table found, so using '" << tableName << "'instance..."
2332  << __E__;
2333  table = nameToTableMap_[tableName];
2334  }
2335 
2336  table->setActiveView(TableVersion(TableVersion::DEFAULT));
2337 
2338  TableView* view = table->getViewP();
2339  __COUT__ << "Activated version: " << view->getVersion() << __E__;
2340  // view->print();
2341 
2342  if(recordName != "") // then add this record
2343  {
2344  // Steps:
2345  // - add row
2346  // - set UID and enable (if possible)
2347  // - set values for parameter columns
2348  // - define links
2349 
2350  __COUTV__(recordName);
2351 
2352  // add row and get column map
2353  unsigned int r = view->addRow();
2354  auto colMap = view->getColumnNamesMap();
2355 
2356  // set UID and enable (if possible)
2357  view->setValue(recordName, r, view->getColUID());
2358  try
2359  {
2360  view->setValue("1", r, view->getColStatus());
2361  }
2362  catch(...)
2363  {
2364  __COUT__ << "No status column to set for '" << recordName << "'" << __E__;
2365  }
2366 
2367  if(groupName != "") // then set groupID for this record
2368  {
2369  int groupIDCol = view->getColLinkGroupID(groupLinkIndex);
2370  __COUT__ << "Setting group ID for group link ID '" << groupLinkIndex
2371  << "' at column " << groupIDCol << " to '" << groupName << ".'"
2372  << __E__;
2373 
2374  view->setValue(groupName, r, groupIDCol);
2375  }
2376 
2377  // then set parameters
2378  auto names = pset.get_names();
2379  for(const auto& colName : names)
2380  {
2381  if(!pset.is_key_to_atom(colName))
2382  continue;
2383 
2384  auto colIt = colMap.find(colName);
2385  if(colIt == colMap.end())
2386  {
2387  __SS__ << "Field '" << colName << "' of record '" << recordName
2388  << "' in table '" << tableName << "' was not found in columns."
2389  << "\n\nHere are the existing column names:\n";
2390  unsigned int i = 0;
2391  for(const auto& col : colMap)
2392  ss << "\n" << ++i << ".\t" << col.first;
2393  ss << __E__;
2394  __SS_THROW__;
2395  }
2396  const std::string value = pset.get<std::string>(colName);
2397  __COUT__ << "Setting '" << recordName << "' parameter at column "
2398  << colIt->second << ", '" << colName << "'\t = " << value
2399  << __E__;
2400  view->setValueAsString(value, r, colIt->second);
2401  } // end set parameters
2402 
2403  // then define links
2404  for(const auto& linkName : names)
2405  {
2406  if(pset.is_key_to_atom(linkName))
2407  continue;
2408 
2409  __COUTV__(linkName);
2410 
2411  // split into column name and table
2412  unsigned int c = linkName.size() - 1;
2413  for(; c >= 1; --c)
2414  if(linkName[c] == '_') // find first underscore to split linkName
2415  break;
2416 
2417  if(c == 0)
2418  {
2419  __SS__ << "Illegal link name '" << linkName
2420  << "' found. The format must be <Column name>_<Target table "
2421  "name>,.. for example '"
2422  << "LinkToFETypeTable_FEOtsUDPTemplateInterfaceTable'"
2423  << __E__;
2424  __SS_THROW__;
2425  }
2426  std::string colName = linkName.substr(0, c);
2427  __COUTV__(colName);
2428 
2429  auto colIt = colMap.find(colName);
2430  if(colIt == colMap.end())
2431  {
2432  __SS__ << "Link '" << colName << "' of record '" << recordName
2433  << "' in table '" << tableName << "' was not found in columns."
2434  << "\n\nHere are the existing column names:\n";
2435  unsigned int i = 0;
2436  for(const auto& col : colMap)
2437  ss << "\n" << i << ".\t" << col.first << __E__;
2438  __SS_THROW__;
2439  }
2440  //__COUT__ << "Setting link at column " << colIt->second << __E__;
2441 
2442  std::pair<unsigned int /*link col*/, unsigned int /*link id col*/>
2443  linkPair;
2444  bool isGroupLink;
2445  view->getChildLink(colIt->second, isGroupLink, linkPair);
2446 
2447  //__COUTV__(isGroupLink);
2448  //__COUTV__(linkPair.first);
2449  //__COUTV__(linkPair.second);
2450 
2451  std::string linkTableName = linkName.substr(c + 1);
2452  __COUTV__(linkTableName);
2453 
2454  auto linkPset = pset.get<fhicl::ParameterSet>(linkName);
2455  auto linkRecords = linkPset.get_pset_names();
2456  if(!isGroupLink && linkRecords.size() > 1)
2457  {
2458  __SS__ << "A Unique Link can only point to one record. "
2459  << "The specified link '" << colName << "' of record '"
2460  << recordName << "' in table '" << tableName << "' has "
2461  << linkRecords.size() << " children records specified. "
2462  << __E__;
2463  __SS_THROW__;
2464  }
2465 
2466  if(linkRecords.size() == 0)
2467  {
2468  __COUT__ << "No child records, so leaving link disconnected."
2469  << __E__;
2470  continue;
2471  }
2472 
2473  __COUT__ << "Setting Link at columns [" << linkPair.first << ","
2474  << linkPair.second << "]" << __E__;
2475  view->setValue(linkTableName, r, linkPair.first);
2476 
2477  if(!isGroupLink)
2478  {
2479  __COUT__ << "Setting up Unique link to " << linkRecords[0] << __E__;
2480 
2481  view->setValue(linkRecords[0], r, linkPair.second);
2482 
2483  recursiveInitFromFhiclPSet(
2484  linkTableName /*tableName*/,
2485  linkPset.get<fhicl::ParameterSet>(
2486  linkRecords[0]) /*fhicl parameter set*/,
2487  linkRecords[0] /*uid*/,
2488  "" /*groupID*/);
2489 
2490  view->print();
2491  }
2492  else
2493  {
2494  std::string childLinkIndex =
2495  view->getColumnInfo(linkPair.first).getChildLinkIndex();
2496  std::string groupName = recordName + "Group";
2497 
2498  view->setValue(groupName, r, linkPair.second);
2499 
2500  for(const auto& groupRecord : linkRecords)
2501  {
2502  __COUT__ << "Setting '" << childLinkIndex << "' Group link to '"
2503  << groupName << "' record '" << groupRecord << "'"
2504  << __E__;
2505 
2506  recursiveInitFromFhiclPSet(
2507  linkTableName /*tableName*/,
2508  linkPset.get<fhicl::ParameterSet>(
2509  groupRecord) /*fhicl parameter set*/,
2510  groupRecord /*uid*/,
2511  groupName /*groupID*/,
2512  childLinkIndex /*groupLinkIndex*/);
2513  }
2514  }
2515 
2516  } // end link handling
2517  }
2518  else if(groupName != "") // then add group of records
2519  {
2520  // get_pset_names();
2521  // get_names
2522  __COUTV__(groupName);
2523  auto psets = pset.get_pset_names();
2524  for(const auto& ps : psets)
2525  {
2526  __COUTV__(ps);
2527  recursiveInitFromFhiclPSet(
2528  tableName /*tableName*/,
2529  pset.get<fhicl::ParameterSet>(ps) /*fhicl parameter set*/,
2530  ps /*uid*/,
2531  groupName /*groupID*/,
2532  groupLinkIndex /*groupLinkIndex*/);
2533  }
2534 
2535  view->print();
2536  }
2537  else
2538  {
2539  __SS__ << "Illegal recursive parameters!" << __E__;
2540  __SS_THROW__;
2541  }
2542  }
2543 
2544  __COUT__ << __COUT_HDR_P__ << "Done adding table '" << tableName << "' record(s)..."
2545  << __E__;
2546 
2547 } // end recursiveInitFromFhiclPSet()
2548 
2549 //==============================================================================
2550 bool ConfigurationManager::isOwnerFirstAppInContext()
2551 {
2552  __COUT__ << "Checking if owner is first App in Context." << __E__;
2553  if(ownerContextUID_ == "" || ownerAppUID_ == "")
2554  return true; // default to 'yes'
2555 
2556  __COUTV__(ownerContextUID_);
2557  __COUTV__(ownerAppUID_);
2558 
2559  auto contextChildren =
2560  getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME + "/" + ownerContextUID_)
2561  .getChildrenNames();
2562 
2563  bool isFirstAppInContext =
2564  contextChildren.size() == 0 || contextChildren[0] == ownerAppUID_;
2565 
2566  __COUTV__(isFirstAppInContext);
2567 
2568  return isFirstAppInContext;
2569 } // end isOwnerFirstAppInContext()