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