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