otsdaq  v2_01_00
ConfigurationManager.cc
1 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
2 #include "otsdaq-core/ConfigurationInterface/ConfigurationInterface.h"//All configurable objects are included here
3 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationGroupKey.h"
4 #include "otsdaq-core/ProgressBar/ProgressBar.h"
5 
6 #include <fstream> // std::ofstream
7 
8 
9 using namespace ots;
10 
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_CONFIG_NAME = "XDAQContextConfiguration";
18 
19 //added env check for otsdaq_flatten_active_to_version to function
20 const std::string ConfigurationManager::ACTIVE_GROUP_FILENAME = ((getenv("SERVICE_DATA_PATH") == NULL)?(std::string(getenv("USER_DATA"))+"/ServiceData"):(std::string(getenv("SERVICE_DATA_PATH")))) + "/ActiveConfigurationGroups.cfg";
21 const std::string ConfigurationManager::ALIAS_VERSION_PREAMBLE = "ALIAS:";
22 const std::string ConfigurationManager::SCRATCH_VERSION_ALIAS = "Scratch";
23 
24 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT = "Context";
25 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE = "Backbone";
26 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE = "Iterate";
27 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION = "Configuration";
28 
29 const std::set<std::string> ConfigurationManager::contextMemberNames_ = {ConfigurationManager::XDAQ_CONTEXT_CONFIG_NAME,"XDAQApplicationConfiguration","XDAQApplicationPropertyConfiguration","DesktopIconConfiguration","MessageFacilityConfiguration","TheSupervisorConfiguration","StateMachineConfiguration","DesktopWindowParameterConfiguration"};
30 const std::set<std::string> ConfigurationManager::backboneMemberNames_ = {"GroupAliasesConfiguration","VersionAliasesConfiguration"};
31 const std::set<std::string> ConfigurationManager::iterateMemberNames_ = {"IterateConfiguration","IterationPlanConfiguration","IterationTargetConfiguration",
32  /*command specific tables*/"IterationCommandBeginLabelConfiguration","IterationCommandChooseFSMConfiguration","IterationCommandConfigureAliasConfiguration","IterationCommandConfigureGroupConfiguration","IterationCommandExecuteFEMacroConfiguration","IterationCommandExecuteMacroConfiguration","IterationCommandModifyGroupConfiguration","IterationCommandRepeatLabelConfiguration","IterationCommandRunConfiguration"};
33 
34 //==============================================================================
35 ConfigurationManager::ConfigurationManager()
36 : username_ (ConfigurationManager::READONLY_USER)
37 , theInterface_ (0)
38 , theConfigurationGroupKey_ (0)
39 , theContextGroupKey_ (0)
40 , theBackboneGroupKey_ (0)
41 , theConfigurationGroup_ ("")
42 , theContextGroup_ ("")
43 , theBackboneGroup_ ("")
44 {
45  theInterface_ = ConfigurationInterface::getInstance(false); //false to use artdaq DB
46  //NOTE: in ConfigurationManagerRW using false currently.. think about consistency! FIXME
47 
48  //initialize special group metadata table
49  {
50  //Note: "ConfigurationGroupMetadata" should never be in conflict
51  // because all other tables end in "...Configuration"
52 
53  //This is a table called ConfigurationGroupMetadata
54  // with 3 fields:
55  // - GroupAuthor
56  // - GroupCreationTime
57  // - CommentDescription
58 
59  groupMetadataTable_.setConfigurationName(ConfigurationInterface::GROUP_METADATA_TABLE_NAME);
60  //ConfigurationView* mockup = configurationGroupMetadataTable_.getMockupViewP();
61  std::vector<ViewColumnInfo>* colInfo =
62  groupMetadataTable_.getMockupViewP()->getColumnsInfoP();
63 
64 
65  colInfo->push_back(ViewColumnInfo(
66  ViewColumnInfo::TYPE_UID, //just to make init() happy
67  "UnusedUID",
68  "UNUSED_UID",
69  ViewColumnInfo::DATATYPE_NUMBER,
70  "",0
71  ));
72  colInfo->push_back(ViewColumnInfo(
73  ViewColumnInfo::TYPE_COMMENT, //just to make init() happy
74  "CommentDescription",
75  "COMMENT_DESCRIPTION",
76  ViewColumnInfo::DATATYPE_STRING,
77  "",0
78  ));
79  colInfo->push_back(ViewColumnInfo(
80  ViewColumnInfo::TYPE_AUTHOR, //just to make init() happy
81  "GroupAuthor",
82  "AUTHOR",
83  ViewColumnInfo::DATATYPE_STRING,
84  "",0
85  ));
86  colInfo->push_back(ViewColumnInfo(
87  ViewColumnInfo::TYPE_TIMESTAMP,
88  "GroupCreationTime",
89  "GROUP_CREATION_TIME",
90  ViewColumnInfo::DATATYPE_TIME,
91  "",0
92  ));
93  auto tmpVersion = groupMetadataTable_.createTemporaryView();
94  groupMetadataTable_.setActiveView(tmpVersion);
95  //only need this one and only row for all time
96  groupMetadataTable_.getViewP()->addRow();
97  }
98 
99 
100  init();
101 }
102 
103 //==============================================================================
104 ConfigurationManager::ConfigurationManager(const std::string& username)
106 {
107  username_ = username;
108 }
109 
110 //==============================================================================
111 ConfigurationManager::~ConfigurationManager()
112 {
113  destroy();
114 }
115 
116 //==============================================================================
117 //init
118 // if accumulatedErrors is not null.. fill it with errors
119 // else throw errors (but do not ask restoreActiveConfigurationGroups to throw errors)
120 void ConfigurationManager::init(std::string *accumulatedErrors)
121 {
122  if(accumulatedErrors) *accumulatedErrors = "";
123 
124  //destroy();
125 
126  // once Interface is false (using artdaq db) .. then can call
127  if(theInterface_->getMode() == false)
128  {
129  try
130  {
131  restoreActiveConfigurationGroups(accumulatedErrors?true:false);
132  }
133  catch(std::runtime_error &e)
134  {
135  if(accumulatedErrors) *accumulatedErrors = e.what();
136  else throw;
137  }
138  }
139 }
140 
141 //==============================================================================
142 //restoreActiveConfigurationGroups
143 // load the active groups from file
144 // Note: this should be used by the Supervisor to maintain
145 // the same configurationGroups surviving software system restarts
146 void ConfigurationManager::restoreActiveConfigurationGroups(bool throwErrors)
147 {
148  destroyConfigurationGroup("",true); //deactivate all
149 
150  std::string fn = ACTIVE_GROUP_FILENAME;
151  FILE *fp = fopen(fn.c_str(),"r");
152 
153  __COUT__ << "ACTIVE_GROUP_FILENAME = " << ACTIVE_GROUP_FILENAME << std::endl;
154  __COUT__ << "ARTDAQ_DATABASE_URI = " << std::string(getenv("ARTDAQ_DATABASE_URI")) << std::endl;
155 
156  if(!fp) return;
157 
158  //__COUT__ << "throwErrors: " << throwErrors << std::endl;
159 
160  char tmp[500];
161  char strVal[500];
162 
163  std::string groupName;
164  std::string errorStr = "";
165  bool skip;
166 
167  __SS__;
168 
169  while(fgets(tmp,500,fp))//for(int i=0;i<4;++i)
170  {
171  //fgets(tmp,500,fp);
172 
173  skip = false;
174  sscanf(tmp,"%s",strVal); //sscanf to remove '\n'
175  for(unsigned int j=0;j<strlen(strVal);++j)
176  if(!(
177  (strVal[j] >= 'a' && strVal[j] <= 'z') ||
178  (strVal[j] >= 'A' && strVal[j] <= 'Z') ||
179  (strVal[j] >= '0' && strVal[j] <= '9')))
180  {
181  strVal[j] = '\0';
182  __COUT_INFO__ << "Illegal character found, so skipping!" << std::endl;
183 
184  skip = true;
185  break;
186  }
187 
188  if(skip) continue;
189 
190  groupName = strVal;
191  fgets(tmp,500,fp);
192  sscanf(tmp,"%s",strVal); //sscanf to remove '\n'
193 
194  for(unsigned int j=0;j<strlen(strVal);++j)
195  if(!(
196  (strVal[j] >= '0' && strVal[j] <= '9')))
197  {
198  strVal[j] = '\0';
199  __COUT_INFO__ << "Illegal character found, so skipping!" << std::endl;
200 
201  skip = true;
202  break;
203  }
204 
205  try
206  {
207  ConfigurationGroupKey::getFullGroupString(groupName,ConfigurationGroupKey(strVal));
208  }
209  catch(...)
210  {
211  __COUT__ << "illegal group accorging to ConfigurationGroupKey::getFullGroupString..." << std::endl;
212  skip = true;
213  }
214 
215  if(skip) continue;
216 
217  try
218  {
219  //load and doActivate
220  loadConfigurationGroup(groupName,ConfigurationGroupKey(strVal),true);
221  }
222  catch(std::runtime_error &e)
223  {
224  ss << "Failed to load config group in ConfigurationManager::init() with name '" <<
225  groupName << "_v" << strVal << "'" << std::endl;
226  ss << e.what() << std::endl;
227 
228  errorStr += ss.str();
229  }
230  catch(...)
231  {
232  ss << "Failed to load config group in ConfigurationManager::init() with name '" <<
233  groupName << "_v" << strVal << "'" << std::endl;
234 
235  errorStr += ss.str();
236  }
237  }
238 
239  fclose(fp);
240 
241  if(throwErrors && errorStr != "")
242  {
243  __COUT_INFO__ << "\n" << ss.str();
244  throw std::runtime_error(errorStr);
245  }
246 }
247 
248 //==============================================================================
249 //destroyConfigurationGroup
250 // destroy all if theGroup == ""
251 // else destroy that group
252 // if onlyDeactivate, then don't delete, just deactivate view
253 void ConfigurationManager::destroyConfigurationGroup(const std::string& theGroup, bool onlyDeactivate)
254 {
255  //delete
256  bool isContext = theGroup == "" || theGroup == theContextGroup_;
257  bool isBackbone = theGroup == "" || theGroup == theBackboneGroup_;
258  bool isIterate = theGroup == "" || theGroup == theIterateGroup_;
259  bool isConfiguration = theGroup == "" || theGroup == theConfigurationGroup_;
260 
261  if(!isContext && !isBackbone && !isIterate && !isConfiguration)
262  {
263  __SS__ << "Invalid configuration group to destroy: " << theGroup << std::endl;
264  __COUT_ERR__ << ss.str();
265  throw std::runtime_error(ss.str());
266  }
267 
268  std::string dbgHeader = onlyDeactivate?"Deactivating":"Destroying";
269  if(theGroup != "")
270  {
271  if(isContext)
272  __COUT__ << dbgHeader << " Context group: " << theGroup << std::endl;
273  if(isBackbone)
274  __COUT__ << dbgHeader << " Backbone group: " << theGroup << std::endl;
275  if(isIterate)
276  __COUT__ << dbgHeader << " Iterate group: " << theGroup << std::endl;
277  if(isConfiguration)
278  __COUT__ << dbgHeader << " Configuration group: " << theGroup << std::endl;
279  }
280 
281  std::set<std::string>::const_iterator contextFindIt, backboneFindIt, iterateFindIt;
282  for(auto it = nameToConfigurationMap_.begin(); it != nameToConfigurationMap_.end(); /*no increment*/)
283  {
284  contextFindIt = contextMemberNames_.find(it->first);
285  backboneFindIt = backboneMemberNames_.find(it->first);
286  iterateFindIt = iterateMemberNames_.find(it->first);
287  if(theGroup == "" || (
288  (isContext && contextFindIt != contextMemberNames_.end()) ||
289  (isBackbone && backboneFindIt != backboneMemberNames_.end()) ||
290  (isIterate && iterateFindIt != iterateMemberNames_.end()) ||
291  (!isContext && !isBackbone &&
292  contextFindIt == contextMemberNames_.end() &&
293  backboneFindIt == backboneMemberNames_.end()&&
294  iterateFindIt == iterateMemberNames_.end())))
295  {
296  //__COUT__ << "\t" << it->first << std::endl;
297  //if(it->second->isActive())
298  // __COUT__ << "\t\t..._v" << it->second->getViewVersion() << std::endl;
299 
300 
301  if(onlyDeactivate) //only deactivate
302  {
303  it->second->deactivate();
304  ++it;
305  }
306  else //else, delete/erase
307  {
308  delete it->second;
309  nameToConfigurationMap_.erase(it++);
310  }
311  }
312  else
313  ++it;
314  }
315 
316  if(isConfiguration)
317  {
318  theConfigurationGroup_ = "";
319  if(theConfigurationGroupKey_ != 0)
320  {
321  __COUT__ << "Destroying Configuration Key: " << *theConfigurationGroupKey_ << std::endl;
322  theConfigurationGroupKey_.reset();
323  }
324 
325  // theDACStreams_.clear();
326  }
327  if(isBackbone)
328  {
329  theBackboneGroup_ = "";
330  if(theBackboneGroupKey_ != 0)
331  {
332  __COUT__ << "Destroying Backbone Key: " << *theBackboneGroupKey_ << std::endl;
333  theBackboneGroupKey_.reset();
334  }
335  }
336  if(isIterate)
337  {
338  theIterateGroup_ = "";
339  if(theIterateGroupKey_ != 0)
340  {
341  __COUT__ << "Destroying Iterate Key: " << *theIterateGroupKey_ << std::endl;
342  theIterateGroupKey_.reset();
343  }
344  }
345  if(isContext)
346  {
347  theContextGroup_ = "";
348  if(theContextGroupKey_ != 0)
349  {
350  __COUT__ << "Destroying Context Key: " << *theContextGroupKey_ << std::endl;
351  theContextGroupKey_.reset();
352  }
353  }
354 }
355 
356 //==============================================================================
357 void ConfigurationManager::destroy(void)
358 {
359  //NOTE: Moved to ConfigurationGUISupervisor [FIXME is this correct?? should we use shared_ptr??]
360  // if( ConfigurationInterface::getInstance(true) != 0 )
361  // delete theInterface_;
362  destroyConfigurationGroup();
363 }
364 
365 
366 //==============================================================================
367 //convertGroupTypeIdToName
368 // return translation:
369 // 0 for context
370 // 1 for backbone
371 // 2 for configuration (others)
372 const std::string& ConfigurationManager::convertGroupTypeIdToName(int groupTypeId)
373 {
374  return groupTypeId==CONTEXT_TYPE?
375  ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT:
376  (groupTypeId==BACKBONE_TYPE?
377  ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE:
378  (groupTypeId==ITERATE_TYPE?
379  ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE:
380  ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION));
381 }
382 
383 //==============================================================================
384 //getTypeOfGroup
385 // return
386 // CONTEXT_TYPE for context
387 // BACKBONE_TYPE for backbone
388 // ITERATE_TYPE for iterate
389 // CONFIGURATION_TYPE for configuration (others)
390 int ConfigurationManager::getTypeOfGroup(
391  const std::map<std::string /*name*/, ConfigurationVersion /*version*/> &memberMap)
392 {
393 
394  bool isContext = true;
395  bool isBackbone = true;
396  bool isIterate = true;
397  bool inGroup;
398  bool inContext = false;
399  bool inBackbone = false;
400  bool inIterate = false;
401  unsigned int matchCount = 0;
402 
403  for(auto &memberPair:memberMap)
404  {
405  //__COUT__ << "Member name: = "<< memberPair.first << std::endl;
407  inGroup = false; //check context
408  for(auto &contextMemberString:contextMemberNames_)
409  if(memberPair.first == contextMemberString)
410  {
411  inGroup = true;
412  inContext = true;
413  ++matchCount;
414  break;
415  }
416  if(!inGroup)
417  {
418  isContext = false;
419  if(inContext) //there was a member in context!
420  {
421  __SS__ << "This group is an incomplete match to a Context group.\n";
422  __COUT_ERR__ << "\n" << ss.str();
423  ss << "\nTo be a Context group, the members must exactly match" <<
424  "the following members:\n";
425  int i = 0;
426  for(auto &memberName:contextMemberNames_)
427  ss << ++i << ". " << memberName << "\n";
428  throw std::runtime_error(ss.str());
429  }
430  }
431 
433  inGroup = false; //check backbone
434  for(auto &backboneMemberString:backboneMemberNames_)
435  if(memberPair.first == backboneMemberString)
436  {
437  inGroup = true;
438  inBackbone = true;
439  ++matchCount;
440  break;
441  }
442  if(!inGroup)
443  {
444  isBackbone = false;
445  if(inBackbone) //there was a member in backbone!
446  {
447  __SS__ << "This group is an incomplete match to a Backbone group.\n";
448  __COUT_ERR__ << "\n" << ss.str();
449  ss << "\nTo be a Backbone group, the members must exactly match" <<
450  "the following members:\n";
451  int i = 0;
452  for(auto &memberName:backboneMemberNames_)
453  ss << ++i << ". " << memberName << "\n";
454  //__COUT_ERR__ << "\n" << ss.str();
455  throw std::runtime_error(ss.str());
456  }
457  }
458 
460  inGroup = false; //check iterate
461  for(auto &iterateMemberString:iterateMemberNames_)
462  if(memberPair.first == iterateMemberString)
463  {
464  inGroup = true;
465  inIterate = true;
466  ++matchCount;
467  break;
468  }
469  if(!inGroup)
470  {
471  isIterate = false;
472  if(inIterate) //there was a member in iterate!
473  {
474  __SS__ << "This group is an incomplete match to a Iterate group.\n";
475  __COUT_ERR__ << "\n" << ss.str();
476  ss << "\nTo be a Iterate group, the members must exactly match" <<
477  "the following members:\n";
478  int i = 0;
479  for(auto &memberName:iterateMemberNames_)
480  ss << ++i << ". " << memberName << "\n";
481  //__COUT_ERR__ << "\n" << ss.str();
482  throw std::runtime_error(ss.str());
483  }
484  }
485  }
486 
487  if(isContext && matchCount != contextMemberNames_.size())
488  {
489  __SS__ << "This group is an incomplete match to a Context group: " <<
490  " Size=" << matchCount << " but should be " << contextMemberNames_.size() <<
491  std::endl;
492  __COUT_ERR__ << "\n" << ss.str();
493  ss << "\nThe members currently are...\n";
494  int i = 0;
495  for(auto &memberPair:memberMap)
496  ss << ++i << ". " << memberPair.first << "\n";
497  ss << "\nThe expected Context members are...\n";
498  i = 0;
499  for(auto &memberName:contextMemberNames_)
500  ss << ++i << ". " << memberName << "\n";
501  //__COUT_ERR__ << "\n" << ss.str();
502  throw std::runtime_error(ss.str());
503  }
504 
505  if(isBackbone && matchCount != backboneMemberNames_.size())
506  {
507  __SS__ << "This group is an incomplete match to a Backbone group: " <<
508  " Size=" << matchCount << " but should be " << backboneMemberNames_.size() <<
509  std::endl;
510  __COUT_ERR__ << "\n" << ss.str();
511  ss << "\nThe members currently are...\n";
512  int i = 0;
513  for(auto &memberPair:memberMap)
514  ss << ++i << ". " << memberPair.first << "\n";
515  ss << "\nThe expected Backbone members are...\n";
516  i = 0;
517  for(auto &memberName:backboneMemberNames_)
518  ss << ++i << ". " << memberName << "\n";
519  //__COUT_ERR__ << "\n" << ss.str();
520  throw std::runtime_error(ss.str());
521  }
522 
523  if(isIterate && matchCount != iterateMemberNames_.size())
524  {
525  __SS__ << "This group is an incomplete match to a Iterate group: " <<
526  " Size=" << matchCount << " but should be " << backboneMemberNames_.size() <<
527  std::endl;
528  __COUT_ERR__ << "\n" << ss.str();
529  ss << "\nThe members currently are...\n";
530  int i = 0;
531  for(auto &memberPair:memberMap)
532  ss << ++i << ". " << memberPair.first << "\n";
533  ss << "\nThe expected Iterate members are...\n";
534  i = 0;
535  for(auto &memberName:iterateMemberNames_)
536  ss << ++i << ". " << memberName << "\n";
537  //__COUT_ERR__ << "\n" << ss.str();
538  throw std::runtime_error(ss.str());
539  }
540 
541  return isContext?CONTEXT_TYPE:(isBackbone?BACKBONE_TYPE:(isIterate?ITERATE_TYPE:CONFIGURATION_TYPE));
542 }
543 
544 //==============================================================================
545 //getTypeNameOfGroup
546 // return string for group type
547 const std::string& ConfigurationManager::getTypeNameOfGroup(
548  const std::map<std::string /*name*/, ConfigurationVersion /*version*/> &memberMap)
549 {
550  return convertGroupTypeIdToName(getTypeOfGroup(memberMap));
551 }
552 
553 //==============================================================================
554 //loadMemberMap
555 // loads tables given by name/version pairs in memberMap
556 // Note: does not activate them.
557 //
558 // if filePath == "", then output to cout
559 void ConfigurationManager::dumpActiveConfiguration(
560  const std::string &filePath, const std::string &dumpType) const
561 {
562  time_t rawtime = time(0);
563  __COUT__ << "filePath = " << filePath << std::endl;
564  __COUT__ << "dumpType = " << dumpType << std::endl;
565 
566 
567  std::ofstream fs;
568  fs.open(filePath, std::fstream::out | std::fstream::trunc);
569 
570  std::ostream *out;
571 
572  //if file was valid use it, else default to cout
573  if(fs.is_open())
574  out = &fs;
575  else
576  {
577  if(filePath != "")
578  {
579  __SS__ << "Invalid file path to dump active configuration. File " << filePath << " could not be opened!" << __E__;
580  __COUT_ERR__ << ss.str();
581  throw std::runtime_error(ss.str());
582  }
583  out = &(std::cout);
584  }
585 
586 
587  (*out) << "#################################" << std::endl;
588  (*out) << "This is an ots configuration dump.\n\n" << std::endl;
589  (*out) << "Source database is $ARTDAQ_DATABASE_URI = \t" << getenv("ARTDAQ_DATABASE_URI") << std::endl;
590  (*out) << "\nOriginal location of dump: \t" << filePath << std::endl;
591  (*out) << "Type of dump: \t" << dumpType << std::endl;
592  (*out) << "Linux time for dump: \t" << rawtime << std::endl;
593 
594  {
595  struct tm * timeinfo = localtime (&rawtime);
596  char buffer [100];
597  strftime(buffer,100,"%c %Z",timeinfo);
598  (*out) << "Display time for dump: \t" << buffer << std::endl;
599  }
600 
601 
602  //define local "lambda" functions
603  // active groups
604  // active tables
605  // active group members
606  // active table contents
607 
608  auto localDumpActiveGroups = [](const ConfigurationManager *cfgMgr, std::ostream *out) {
609  std::map<std::string, std::pair<std::string, ConfigurationGroupKey>> activeGroups =
610  cfgMgr->getActiveConfigurationGroups();
611 
612  (*out) << "\n\n************************" << std::endl;
613  (*out) << "Active Groups:" << std::endl;
614  for(auto &group:activeGroups)
615  {
616  (*out) << "\t" << group.first << " := " <<
617  group.second.first << " (" <<
618  group.second.second << ")" << std::endl;
619  }
620  };
621 
622  auto localDumpActiveTables = [](const ConfigurationManager *cfgMgr, std::ostream *out) {
623  std::map<std::string, ConfigurationVersion> activeTables =
624  cfgMgr->getActiveVersions();
625 
626  (*out) << "\n\n************************" << std::endl;
627  (*out) << "Active Tables:" << std::endl;
628  (*out) << "Active Tables count = " << activeTables.size() << std::endl;
629 
630  unsigned int i = 0;
631  for(auto &table:activeTables)
632  {
633  (*out) << "\t" << ++i << ". " << table.first << "-v" <<
634  table.second << std::endl;
635  }
636  };
637 
638  auto localDumpActiveGroupMembers = [](const ConfigurationManager *cfgMgr, std::ostream *out) {
639  std::map<std::string, std::pair<std::string, ConfigurationGroupKey>> activeGroups =
640  cfgMgr->getActiveConfigurationGroups();
641  (*out) << "\n\n************************" << std::endl;
642  (*out) << "Active Group Members:" << std::endl;
643  int tableCount = 0;
644  for(auto &group:activeGroups)
645  {
646  (*out) << "\t" << group.first << " := " <<
647  group.second.first << " (" <<
648  group.second.second << ")" << std::endl;
649 
650  if(group.second.first == "")
651  {
652  (*out) << "\t" << "Empty group name. Assuming no active group." << __E__;
653  continue;
654  }
655 
656  std::map<std::string /*name*/, ConfigurationVersion /*version*/> memberMap =
657  cfgMgr->theInterface_->getConfigurationGroupMembers(
658  ConfigurationGroupKey::getFullGroupString(
659  group.second.first,
660  group.second.second));
661 
662  (*out) << "\tMember table count = " << memberMap.size() << std::endl;
663  tableCount += memberMap.size();
664 
665  unsigned int i = 0;
666  for(auto &member:memberMap)
667  {
668  (*out) << "\t\t" << ++i << ". " << member.first << "-v" <<
669  member.second << std::endl;
670  }
671  }
672  (*out) << "\nActive Group Members total table count = " << tableCount << std::endl;
673  };
674 
675  auto localDumpActiveTableContents = [](const ConfigurationManager *cfgMgr, std::ostream *out) {
676  std::map<std::string, ConfigurationVersion> activeTables =
677  cfgMgr->getActiveVersions();
678 
679  (*out) << "\n\n************************" << std::endl;
680  (*out) << "Active Table Contents (table count = " << activeTables.size()
681  << "):" << std::endl;
682  unsigned int i = 0;
683  for(auto &table:activeTables)
684  {
685  (*out) << "\n\n==============================================================================" << std::endl;
686  (*out) << "==============================================================================" << std::endl;
687  (*out) << "\t" << ++i << ". " << table.first << "-v" <<
688  table.second << std::endl;
689 
690  cfgMgr->nameToConfigurationMap_.find(table.first)->second->print(*out);
691  }
692  };
693 
694 
695 
696  if(dumpType == "GroupKeys")
697  {
698  localDumpActiveGroups(this,out);
699  }
700  else if(dumpType == "TableVersions")
701  {
702  localDumpActiveTables(this,out);
703  }
704  else if(dumpType == "GroupKeysAndTableVersions")
705  {
706  localDumpActiveGroups(this,out);
707  localDumpActiveTables(this,out);
708  }
709  else if(dumpType == "All")
710  {
711  localDumpActiveGroups(this,out);
712  localDumpActiveGroupMembers(this,out);
713  localDumpActiveTables(this,out);
714  localDumpActiveTableContents(this,out);
715  }
716  else
717  {
718  __SS__ << "Invalid dump type '" << dumpType <<
719  "' given during dumpActiveConfiguration(). Valid types are as follows:\n" <<
720 
721  //List all choices
722  "GroupKeys" << ", " <<
723  "TableVersions" << ", " <<
724  "GroupsKeysAndTableVersions" << ", " <<
725  "All" <<
726 
727  "\n\nPlease change the State Machine configuration to a valid dump type." <<
728  std::endl;
729  throw std::runtime_error(ss.str());
730  }
731 
732  if(fs.is_open())
733  fs.close();
734 }
735 
736 //==============================================================================
737 //loadMemberMap
738 // loads tables given by name/version pairs in memberMap
739 // Note: does not activate them.
740 void ConfigurationManager::loadMemberMap(
741  const std::map<std::string /*name*/, ConfigurationVersion /*version*/> &memberMap)
742 {
743  ConfigurationBase *tmpConfigBasePtr;
744  // for each member
745  // get()
746  for(auto &memberPair:memberMap)
747  {
748  //__COUT__ << "\tMember config " << memberPair.first << ":" <<
749  // memberPair.second << std::endl;
750 
751  //get the proper temporary pointer
752  // use 0 if doesn't exist yet.
753  // Note: do not want to give nameToConfigurationMap_[memberPair.first]
754  // in case there is failure in get... (exceptions may be thrown)
755  //Note: Default constructor is called by Map, i.e. nameToConfigurationMap_[memberPair.first] = 0; //create pointer and set to 0
756  tmpConfigBasePtr = 0;
757  if(nameToConfigurationMap_.find(memberPair.first) != nameToConfigurationMap_.end())
758  tmpConfigBasePtr = nameToConfigurationMap_[memberPair.first];
759 
760  theInterface_->get(tmpConfigBasePtr, //configurationPtr
761  memberPair.first, //configurationName
762  0, //ConfigurationGroupKey
763  0, //configurations
764  false, //dontFill=false to fill
765  memberPair.second, //version
766  false //resetConfiguration
767  );
768 
769  nameToConfigurationMap_[memberPair.first] = tmpConfigBasePtr;
770  if(nameToConfigurationMap_[memberPair.first]->getViewP())
771  {
772  //__COUT__ << "\t\tActivated version: " << nameToConfigurationMap_[memberPair.first]->getViewVersion() << std::endl;
773  }
774  else
775  {
776  __SS__ << nameToConfigurationMap_[memberPair.first]->getConfigurationName() <<
777  ": View version not activated properly!";
778  throw std::runtime_error(ss.str());
779  }
780  }
781 }
782 
783 //==============================================================================
784 //loadConfigurationGroup
785 // load all members of configuration group
786 // if doActivate
787 // DOES set theConfigurationGroup_, theContextGroup_, or theBackboneGroup_ on success
788 // this also happens with ConfigurationManagerRW::activateConfigurationGroup
789 // for each member
790 // configBase->init()
791 //
792 // if progressBar != 0, then do step handling, for finer granularity
793 //
794 // if(doNotLoadMember) return memberMap; //this is useful if just getting group metadata
795 // else NOTE: active views are changed! (when loading member map)
796 //
797 // throws exception on failure.
798 // map<name , ConfigurationVersion >
799 void ConfigurationManager::loadConfigurationGroup(
800  const std::string &configGroupName,
801  ConfigurationGroupKey configGroupKey,
802  bool doActivate,
803  std::map<std::string, ConfigurationVersion> *groupMembers,
804  ProgressBar *progressBar,
805  std::string *accumulatedTreeErrors,
806  std::string *groupComment,
807  std::string *groupAuthor,
808  std::string *groupCreateTime,
809  bool doNotLoadMember,
810  std::string *groupTypeString)
811 {
812  //clear to defaults
813  if(accumulatedTreeErrors) *accumulatedTreeErrors = "";
814  if(groupComment) *groupComment = "NO COMMENT FOUND";
815  if(groupAuthor) *groupAuthor = "NO AUTHOR FOUND";
816  if(groupCreateTime) *groupCreateTime = "0";
817  if(groupTypeString) *groupTypeString = "UNKNOWN";
818 
819 
820  // if(configGroupName == "defaultConfig")
821  // { //debug active versions
822  // std::map<std::string, ConfigurationVersion> allActivePairs = getActiveVersions();
823  // for(auto& activePair: allActivePairs)
824  // {
825  // __COUT__ << "Active table = " <<
826  // activePair.first << "-v" <<
827  // getConfigurationByName(activePair.first)->getView().getVersion() << std::endl;
828  // }
829  // }
830 
831 
832  // load all members of configuration group
833  // if doActivate
834  // determine the type configuration
835  // deactivate all of that type (invalidate active view)
836  //
837  // for each member
838  // get()
839  // if doActivate, configBase->init()
840  //
841  // if doActivate
842  // set theConfigurationGroup_, theContextGroup_, or theBackboneGroup_ on success
843 
844  // __COUT_INFO__ << "Loading Configuration Group: " << configGroupName <<
845  // "(" << configGroupKey << ")" << std::endl;
846 
847  std::map<std::string /*name*/, ConfigurationVersion /*version*/> memberMap =
848  theInterface_->getConfigurationGroupMembers(
849  ConfigurationGroupKey::getFullGroupString(configGroupName,configGroupKey),
850  true); //include meta data table
851 
852 
853  if(progressBar) progressBar->step();
854 
855  //remove meta data table and extract info
856  auto metaTablePair = memberMap.find(groupMetadataTable_.getConfigurationName());
857  if(metaTablePair !=
858  memberMap.end())
859  {
860  //__COUT__ << "Found group meta data. v" << metaTablePair->second << std::endl;
861 
862  memberMap.erase(metaTablePair); //remove from member map that is returned
863 
864  if(groupMembers) *groupMembers = memberMap; //copy for return
865 
866  //clear table
867  while(groupMetadataTable_.getView().getNumberOfRows())
868  groupMetadataTable_.getViewP()->deleteRow(0);
869  try
870  {
871  theInterface_->fill(&groupMetadataTable_,metaTablePair->second);
872  }
873  catch(const std::runtime_error& e)
874  {
875  __COUT_WARN__ << "Ignoring metadata error: " << e.what() << __E__;
876  }
877  catch(...)
878  {
879  __COUT_WARN__ << "Ignoring unnkown metadata error. " << __E__;
880  }
881 
882  //check that there is only 1 row
883  if(groupMetadataTable_.getView().getNumberOfRows() != 1)
884  {
885  groupMetadataTable_.print();
886  __SS__ << "groupMetadataTable_ has wrong number of rows! Must be 1." << std::endl;
887  __COUT_ERR__ << "\n" << ss.str();
888 
889  if(groupComment) *groupComment = "NO COMMENT FOUND";
890  if(groupAuthor) *groupAuthor = "NO AUTHOR FOUND";
891  if(groupCreateTime) *groupCreateTime = "0";
892 
893  int groupType = -1;
894  if(groupTypeString) //do before exit case
895  {
896  groupType = getTypeOfGroup(memberMap);
897  *groupTypeString = convertGroupTypeIdToName(groupType);
898  }
899  return;// memberMap;
900  //throw std::runtime_error(ss.str());
901  }
902  //groupMetadataTable_.print();
903 
904 
905  //extract fields
906  if(groupComment) *groupComment = groupMetadataTable_.getView().getValueAsString(0,1);
907  if(groupAuthor) *groupAuthor = groupMetadataTable_.getView().getValueAsString(0,2);
908  if(groupCreateTime) *groupCreateTime = groupMetadataTable_.getView().getValueAsString(0,3);
909  }
910  else if(groupMembers) *groupMembers = memberMap; //copy for return
911 
912  if(progressBar) progressBar->step();
913 
914  //__COUT__ << "memberMap loaded size = " << memberMap.size() << std::endl;
915 
916  int groupType = -1;
917  if(groupTypeString) //do before exit case
918  {
919  groupType = getTypeOfGroup(memberMap);
920  *groupTypeString = convertGroupTypeIdToName(groupType);
921  }
922 
923  // if(configGroupName == "defaultConfig")
924  // { //debug active versions
925  // std::map<std::string, ConfigurationVersion> allActivePairs = getActiveVersions();
926  // for(auto& activePair: allActivePairs)
927  // {
928  // __COUT__ << "Active table = " <<
929  // activePair.first << "-v" <<
930  // getConfigurationByName(activePair.first)->getView().getVersion() << std::endl;
931  // }
932  // }
933 
934 
935  if(doNotLoadMember) return;// memberMap; //this is useful if just getting group metadata
936 
937 
938  //if not already done, determine the type configuration group
939  if(!groupTypeString) groupType = getTypeOfGroup(memberMap);
940 
941  if(doActivate)
942  __COUT__ << "------------------------------------- init start \t [for all plug-ins in " <<
943  convertGroupTypeIdToName(groupType) << " group '" <<
944  configGroupName << "(" << configGroupKey << ")" << "']" << std::endl;
945 
946  if(doActivate)
947  {
948  std::string groupToDeactivate =
949  groupType==CONTEXT_TYPE?theContextGroup_:
950  (groupType==BACKBONE_TYPE?theBackboneGroup_:
951  (groupType==ITERATE_TYPE?
952  theIterateGroup_:theConfigurationGroup_));
953 
954  // deactivate all of that type (invalidate active view)
955  if(groupToDeactivate != "") //deactivate only if pre-existing group
956  {
957  //__COUT__ << "groupToDeactivate '" << groupToDeactivate << "'" << std::endl;
958  destroyConfigurationGroup(groupToDeactivate,true);
959  }
960  // else
961  // {
962  // //Getting here, is kind of strange:
963  // // - this group may have only been partially loaded before?
964  // }
965  }
966  // if(configGroupName == "defaultConfig")
967  // { //debug active versions
968  // std::map<std::string, ConfigurationVersion> allActivePairs = getActiveVersions();
969  // for(auto& activePair: allActivePairs)
970  // {
971  // __COUT__ << "Active table = " <<
972  // activePair.first << "-v" <<
973  // getConfigurationByName(activePair.first)->getView().getVersion() << std::endl;
974  // }
975  // }
976 
977  if(progressBar) progressBar->step();
978 
979  //__COUT__ << "Activating chosen group:" << std::endl;
980 
981 
982  loadMemberMap(memberMap);
983 
984  if(progressBar) progressBar->step();
985 
986  if(accumulatedTreeErrors)
987  {
988  //__COUT__ << "Checking chosen group for tree errors..." << std::endl;
989 
990  getChildren(&memberMap, accumulatedTreeErrors);
991  if(*accumulatedTreeErrors != "")
992  {
993  __COUT_ERR__ << "Errors detected while loading Configuration Group: " << configGroupName <<
994  "(" << configGroupKey << "). Aborting." << std::endl;
995  return;// memberMap; //return member name map to version
996  }
997  }
998 
999  if(progressBar) progressBar->step();
1000 
1001  // for each member
1002  // if doActivate, configBase->init()
1003  if(doActivate)
1004  for(auto &memberPair:memberMap)
1005  {
1006  //do NOT allow activating Scratch versions if tracking is ON!
1007  if(ConfigurationInterface::isVersionTrackingEnabled() &&
1008  memberPair.second.isScratchVersion())
1009  {
1010  __SS__ << "Error while activating member Table '" <<
1011  nameToConfigurationMap_[memberPair.first]->getConfigurationName() <<
1012  "-v" << memberPair.second <<
1013  " for Configuration Group '" << configGroupName <<
1014  "(" << configGroupKey << ")'. When version tracking is enabled, Scratch views" <<
1015  " are not allowed! Please only use unique, persistent versions when version tracking is enabled."
1016  << std::endl;
1017  __COUT_ERR__ << "\n" << ss.str();
1018  throw std::runtime_error(ss.str());
1019  }
1020 
1021 
1022  //attempt to init using the configuration's specific init
1023  // this could be risky user code, try and catch
1024  try
1025  {
1026  nameToConfigurationMap_[memberPair.first]->init(this);
1027  }
1028  catch(std::runtime_error& e)
1029  {
1030  __SS__ << "Error detected calling " <<
1031  nameToConfigurationMap_[memberPair.first]->getConfigurationName() <<
1032  ".init()!\n\n " << e.what() << std::endl;
1033  throw std::runtime_error(ss.str());
1034  }
1035  catch(...)
1036  {
1037  __SS__ << "Error detected calling " <<
1038  nameToConfigurationMap_[memberPair.first]->getConfigurationName() <<
1039  ".init()!\n\n " << std::endl;
1040  throw std::runtime_error(ss.str());
1041  }
1042 
1043  }
1044 
1045  if(progressBar) progressBar->step();
1046 
1047 
1048  // if doActivate
1049  // set theConfigurationGroup_, theContextGroup_, or theBackboneGroup_ on success
1050 
1051  if(doActivate)
1052  {
1053  if(groupType == CONTEXT_TYPE) //
1054  {
1055  // __COUT_INFO__ << "Type=Context, Group loaded: " << configGroupName <<
1056  // "(" << configGroupKey << ")" << std::endl;
1057  theContextGroup_ = configGroupName;
1058  theContextGroupKey_ = std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(configGroupKey));
1059  }
1060  else if(groupType == BACKBONE_TYPE)
1061  {
1062  // __COUT_INFO__ << "Type=Backbone, Group loaded: " << configGroupName <<
1063  // "(" << configGroupKey << ")" << std::endl;
1064  theBackboneGroup_ = configGroupName;
1065  theBackboneGroupKey_ = std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(configGroupKey));
1066  }
1067  else if(groupType == ITERATE_TYPE)
1068  {
1069  // __COUT_INFO__ << "Type=Iterate, Group loaded: " << configGroupName <<
1070  // "(" << configGroupKey << ")" << std::endl;
1071  theIterateGroup_ = configGroupName;
1072  theIterateGroupKey_ = std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(configGroupKey));
1073  }
1074  else //is theConfigurationGroup_
1075  {
1076  // __COUT_INFO__ << "Type=Configuration, Group loaded: " << configGroupName <<
1077  // "(" << configGroupKey << ")" << std::endl;
1078  theConfigurationGroup_ = configGroupName;
1079  theConfigurationGroupKey_ = std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(configGroupKey));
1080  }
1081  }
1082 
1083  if(progressBar) progressBar->step();
1084 
1085  if(doActivate)
1086  __COUT__ << "------------------------------------- init complete \t [for all plug-ins in " <<
1087  convertGroupTypeIdToName(groupType) << " group '" <<
1088  configGroupName << "(" << configGroupKey << ")" << "']" << std::endl;
1089 
1090  return;// memberMap;
1091 }
1092 
1093 
1094 //==============================================================================
1095 //setActiveGlobalConfiguration
1096 // get theActiveGlobalConfig_
1097 // map<type, pair <groupName , ConfigurationGroupKey> >
1098 //
1099 // Note: invalid ConfigurationGroupKey means no active group currently
1100 std::map<std::string, std::pair<std::string, ConfigurationGroupKey> > ConfigurationManager::getActiveConfigurationGroups(void) const
1101 {
1102  // map<type, pair <groupName , ConfigurationGroupKey> >
1103  std::map<std::string, std::pair<std::string, ConfigurationGroupKey> > retMap;
1104 
1105  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT] =
1106  std::pair<std::string,ConfigurationGroupKey>(theContextGroup_ ,theContextGroupKey_ ?*theContextGroupKey_ : ConfigurationGroupKey());
1107  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE] =
1108  std::pair<std::string,ConfigurationGroupKey>(theBackboneGroup_ ,theBackboneGroupKey_ ?*theBackboneGroupKey_ : ConfigurationGroupKey());
1109  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE] =
1110  std::pair<std::string,ConfigurationGroupKey>(theIterateGroup_ ,theIterateGroupKey_ ?*theIterateGroupKey_ : ConfigurationGroupKey());
1111  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION] =
1112  std::pair<std::string,ConfigurationGroupKey>(theConfigurationGroup_,theConfigurationGroupKey_?*theConfigurationGroupKey_: ConfigurationGroupKey());
1113  return retMap;
1114 }
1115 
1116 //==============================================================================
1117 const std::string& ConfigurationManager::getActiveGroupName(const std::string& type) const
1118 {
1119  if(type == "" || type == ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
1120  return theConfigurationGroup_;
1121  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
1122  return theContextGroup_;
1123  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
1124  return theBackboneGroup_;
1125  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
1126  return theIterateGroup_;
1127 
1128  __SS__ << "Invalid type requested '" << type << "'" << std::endl;
1129  __COUT_ERR__ << ss.str();
1130  throw std::runtime_error(ss.str());
1131 }
1132 
1133 //==============================================================================
1134 ConfigurationGroupKey ConfigurationManager::getActiveGroupKey(const std::string& type) const
1135 {
1136  if(type == "" || type == ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
1137  return theConfigurationGroupKey_?*theConfigurationGroupKey_: ConfigurationGroupKey();
1138  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
1139  return theContextGroupKey_ ?*theContextGroupKey_ : ConfigurationGroupKey();
1140  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
1141  return theBackboneGroupKey_ ?*theBackboneGroupKey_ : ConfigurationGroupKey();
1142  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
1143  return theIterateGroupKey_ ?*theIterateGroupKey_ : ConfigurationGroupKey();
1144 
1145  __SS__ << "Invalid type requested '" << type << "'" << std::endl;
1146  __COUT_ERR__ << ss.str();
1147  throw std::runtime_error(ss.str());
1148 }
1149 
1150 //==============================================================================
1151 ConfigurationTree ConfigurationManager::getContextNode(
1152  const std::string &contextUID, const std::string &applicationUID) const
1153 {
1154  return getNode(
1155  "/" + getConfigurationByName(XDAQ_CONTEXT_CONFIG_NAME)->getConfigurationName() +
1156  "/" + contextUID);
1157 }
1158 
1159 //==============================================================================
1160 ConfigurationTree ConfigurationManager::getSupervisorNode(
1161  const std::string &contextUID, const std::string &applicationUID) const
1162 {
1163  return getNode(
1164  "/" + getConfigurationByName(XDAQ_CONTEXT_CONFIG_NAME)->getConfigurationName() +
1165  "/" + contextUID +
1166  "/LinkToApplicationConfiguration/" + applicationUID);
1167 }
1168 
1169 //==============================================================================
1170 ConfigurationTree ConfigurationManager::getSupervisorConfigurationNode(
1171  const std::string &contextUID, const std::string &applicationUID) const
1172 {
1173  return getNode(
1174  "/" + getConfigurationByName(XDAQ_CONTEXT_CONFIG_NAME)->getConfigurationName() +
1175  "/" + contextUID +
1176  "/LinkToApplicationConfiguration/" + applicationUID +
1177  "/LinkToSupervisorConfiguration");
1178 }
1179 
1180 //==============================================================================
1181 ConfigurationTree ConfigurationManager::getNode(const std::string& nodeString,
1182  bool doNotThrowOnBrokenUIDLinks) const
1183 {
1184  //__COUT__ << "nodeString=" << nodeString << " " << nodeString.length() << std::endl;
1185 
1186  //get nodeName (in case of / syntax)
1187  if(nodeString.length() < 1)
1188  {
1189  __SS__ << ("Invalid empty node name") << std::endl;
1190  __COUT_ERR__ << ss.str();
1191  throw std::runtime_error(ss.str());
1192  }
1193 
1194  //ignore multiple starting slashes
1195  unsigned int startingIndex = 0;
1196  while(startingIndex < nodeString.length() &&
1197  nodeString[startingIndex] == '/') ++startingIndex;
1198 
1199  std::string nodeName = nodeString.substr(startingIndex, nodeString.find('/',startingIndex)-startingIndex);
1200  //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << std::endl;
1201  if(nodeName.length() < 1)
1202  {
1203  //return root node
1204  return ConfigurationTree(this,0);
1205 
1206  // __SS__ << "Invalid node name: " << nodeName << std::endl;
1207  // __COUT_ERR__ << ss.str();
1208  // throw std::runtime_error(ss.str());
1209  }
1210 
1211  std::string childPath = nodeString.substr(nodeName.length() + startingIndex);
1212 
1213  //__COUT__ << "childPath=" << childPath << " " << childPath.length() << std::endl;
1214 
1215  ConfigurationTree configTree(this, getConfigurationByName(nodeName));
1216 
1217  if(childPath.length() > 1)
1218  return configTree.getNode(childPath,doNotThrowOnBrokenUIDLinks);
1219  else
1220  return configTree;
1221 }
1222 
1223 //==============================================================================
1224 //getFirstPathToNode
1225 std::string ConfigurationManager::getFirstPathToNode(const ConfigurationTree &node, const std::string &startPath) const
1226 //void ConfigurationManager::getFirstPathToNode(const ConfigurationTree &node, const ConfigurationTree &startNode) const
1227 {
1228  std::string path = "/";
1229  return path;
1230 }
1231 
1232 //==============================================================================
1233 //getChildren
1234 // if memberMap is passed then only consider children in the map
1235 //
1236 // if accumulatedTreeErrors is non null, check for disconnects occurs.
1237 // check is 2 levels deep which should get to the links starting at tables.
1238 std::vector<std::pair<std::string,ConfigurationTree> > ConfigurationManager::getChildren(
1239  std::map<std::string, ConfigurationVersion> *memberMap,
1240  std::string *accumulatedTreeErrors) const
1241 {
1242  std::vector<std::pair<std::string,ConfigurationTree> > retMap;
1243  if(accumulatedTreeErrors) *accumulatedTreeErrors = "";
1244 
1245  if(!memberMap || memberMap->empty()) //return all present active members
1246  {
1247  for(auto &configPair:nameToConfigurationMap_)
1248  {
1249  //__COUT__ << configPair.first << " " << (int)(configPair.second?1:0) << std::endl;
1250 
1251  if(configPair.second->isActive()) //only consider if active
1252  {
1253  ConfigurationTree newNode(this, configPair.second);
1254 
1255 
1256  if(accumulatedTreeErrors) //check for disconnects
1257  {
1258  try
1259  {
1260  std::vector<std::pair<std::string,ConfigurationTree> > newNodeChildren =
1261  newNode.getChildren();
1262  for(auto &newNodeChild: newNodeChildren)
1263  {
1264  std::vector<std::pair<std::string,ConfigurationTree> > twoDeepChildren =
1265  newNodeChild.second.getChildren();
1266 
1267  for(auto &twoDeepChild: twoDeepChildren)
1268  {
1269  //__COUT__ << configPair.first << " " << newNodeChild.first << " " <<
1270  // twoDeepChild.first << std::endl;
1271  if(twoDeepChild.second.isLinkNode() &&
1272  twoDeepChild.second.isDisconnected() &&
1273  twoDeepChild.second.getDisconnectedTableName() !=
1274  ViewColumnInfo::DATATYPE_LINK_DEFAULT)
1275  *accumulatedTreeErrors += "\n\nAt node '" +
1276  configPair.first + "' with entry UID '" +
1277  newNodeChild.first + "' there is a disconnected child node at link column '" +
1278  twoDeepChild.first + "'" +
1279  " that points to table named '" +
1280  twoDeepChild.second.getDisconnectedTableName() +
1281  "' ...";
1282  }
1283  }
1284  }
1285  catch(std::runtime_error &e)
1286  {
1287  *accumulatedTreeErrors += "\n\nAt node '" +
1288  configPair.first + "' error detected descending through children:\n" +
1289  e.what();
1290  }
1291  }
1292 
1293  retMap.push_back(std::pair<std::string,ConfigurationTree>(configPair.first,
1294  newNode));
1295  }
1296 
1297  //__COUT__ << configPair.first << std::endl;
1298  }
1299  }
1300  else //return only members from the member map (they must be present and active!)
1301  {
1302 
1303  for(auto &memberPair: *memberMap)
1304  {
1305  auto mapIt = nameToConfigurationMap_.find(memberPair.first);
1306  if(mapIt == nameToConfigurationMap_.end())
1307  {
1308  __SS__ << "Get Children with member map requires a child '" <<
1309  memberPair.first << "' that is not present!" << std::endl;
1310  throw std::runtime_error(ss.str());
1311  }
1312  if(!(*mapIt).second->isActive())
1313  {
1314  __SS__ << "Get Children with member map requires a child '" <<
1315  memberPair.first << "' that is not active!" << std::endl;
1316  throw std::runtime_error(ss.str());
1317  }
1318 
1319  ConfigurationTree newNode(this, (*mapIt).second);
1320 
1321  if(accumulatedTreeErrors) //check for disconnects
1322  {
1323  try
1324  {
1325  std::vector<std::pair<std::string,ConfigurationTree> > newNodeChildren =
1326  newNode.getChildren();
1327  for(auto &newNodeChild: newNodeChildren)
1328  {
1329  std::vector<std::pair<std::string,ConfigurationTree> > twoDeepChildren =
1330  newNodeChild.second.getChildren();
1331 
1332  for(auto &twoDeepChild: twoDeepChildren)
1333  {
1334  //__COUT__ << memberPair.first << " " << newNodeChild.first << " " <<
1335  // twoDeepChild.first << std::endl;
1336  if(twoDeepChild.second.isLinkNode() &&
1337  twoDeepChild.second.isDisconnected() &&
1338  twoDeepChild.second.getDisconnectedTableName() !=
1339  ViewColumnInfo::DATATYPE_LINK_DEFAULT)
1340  {
1341  *accumulatedTreeErrors += "\n\nAt node '" +
1342  memberPair.first + "' with entry UID '" +
1343  newNodeChild.first + "' there is a disconnected child node at link column '" +
1344  twoDeepChild.first + "'" +
1345  " that points to table named '" +
1346  twoDeepChild.second.getDisconnectedTableName() +
1347  "' ...";
1348 
1349  //check if disconnected table is in group, if not software error
1350 
1351  bool found = false;
1352  for(auto &searchMemberPair: *memberMap)
1353  if(searchMemberPair.first ==
1354  twoDeepChild.second.getDisconnectedTableName())
1355  { found = true; break;}
1356  if(!found)
1357  *accumulatedTreeErrors +=
1358  std::string("\nNote: It may be safe to ignore this error ") +
1359  "since the link's target table " +
1360  twoDeepChild.second.getDisconnectedTableName() +
1361  " is not a member of this group (and may not be loaded yet).";
1362  }
1363  }
1364  }
1365  }
1366  catch(std::runtime_error &e)
1367  {
1368  *accumulatedTreeErrors += "\n\nAt node '" +
1369  memberPair.first + "' error detected descending through children:\n" +
1370  e.what();
1371  }
1372  }
1373 
1374  retMap.push_back(std::pair<std::string,ConfigurationTree>(memberPair.first,
1375  newNode));
1376  }
1377  }
1378 
1379  return retMap;
1380 }
1381 
1382 //==============================================================================
1383 //getConfigurationByName
1384 // Get read-only pointer to configuration.
1385 // If Read/Write access is needed use ConfigurationManagerWithWriteAccess
1386 // (For general use, Write access should be avoided)
1387 const ConfigurationBase* ConfigurationManager::getConfigurationByName(const std::string &configurationName) const
1388 {
1389  std::map<std::string, ConfigurationBase*>::const_iterator it;
1390  if((it = nameToConfigurationMap_.find(configurationName)) == nameToConfigurationMap_.end())
1391  {
1392  __SS__ << "\n\nCan not find configuration named '" <<
1393  configurationName <<
1394  "'\n\n\n\nYou need to load the configuration before it can be used." <<
1395  " It probably is missing from the member list of the Configuration Group that was loaded.\n" <<
1396  "\nYou may need to enter wiz mode to remedy the situation, use the following:\n" <<
1397  "\n\t StartOTS.sh --wiz" <<
1398  "\n\n\n\n"
1399  << std::endl;
1400  //prints out too often
1401  //if(configurationName != ViewColumnInfo::DATATYPE_LINK_DEFAULT)
1402  // __COUT_WARN__ << "\n" << ss.str();
1403  throw std::runtime_error(ss.str());
1404  }
1405  return it->second;
1406 }
1407 
1408 //==============================================================================
1409 //loadConfigurationBackbone
1410 // loads the active backbone configuration group
1411 // returns the active group key that was loaded
1412 ConfigurationGroupKey ConfigurationManager::loadConfigurationBackbone()
1413 {
1414  if(!theBackboneGroupKey_) //no active backbone
1415  {
1416  __COUT_WARN__ << "getConfigurationGroupKey() Failed! No active backbone currently." << std::endl;
1417  return ConfigurationGroupKey();
1418  }
1419 
1420  //may already be loaded, but that's ok, load anyway to be sure
1421  loadConfigurationGroup(theBackboneGroup_,*theBackboneGroupKey_);
1422 
1423  return *theBackboneGroupKey_;
1424 }
1425 
1426 
1427 
1428 //Getters
1429 //==============================================================================
1430 //getConfigurationGroupKey
1431 // use backbone to determine default key for systemAlias.
1432 // - runType translates to group key alias,
1433 // which maps to a group name and key pair
1434 //
1435 // NOTE: temporary special aliases are also allowed
1436 // with the following format:
1437 // GROUP:<name>:<key>
1438 //
1439 // return INVALID on failure
1440 // else, pair<group name , ConfigurationGroupKey>
1441 std::pair<std::string, ConfigurationGroupKey> ConfigurationManager::getConfigurationGroupFromAlias(
1442  std::string systemAlias, ProgressBar* progressBar)
1443 {
1444 
1445  //steps
1446  // check if special alias
1447  // if so, parse and return name/key
1448  // else, load active backbone
1449  // find runType in GroupAliasesConfiguration
1450  // return key
1451 
1452  if(progressBar) progressBar->step();
1453 
1454  if(systemAlias.find("GROUP:") == 0)
1455  {
1456  if(progressBar) progressBar->step();
1457 
1458  unsigned int i = strlen("GROUP:");
1459  unsigned int j = systemAlias.find(':',i);
1460 
1461  if(progressBar) progressBar->step();
1462  if(j>i) //success
1463  return std::pair<std::string, ConfigurationGroupKey>(
1464  systemAlias.substr(i,j-i),
1465  ConfigurationGroupKey(systemAlias.substr(j+1)));
1466  else //failure
1467  return std::pair<std::string, ConfigurationGroupKey>("",ConfigurationGroupKey());
1468  }
1469 
1470 
1471  loadConfigurationBackbone();
1472 
1473  if(progressBar) progressBar->step();
1474 
1475  try
1476  {
1477  // find runType in GroupAliasesConfiguration
1478  ConfigurationTree entry = getNode("GroupAliasesConfiguration").getNode(systemAlias);
1479 
1480  if(progressBar) progressBar->step();
1481 
1482  return std::pair<std::string, ConfigurationGroupKey>(entry.getNode("GroupName").getValueAsString(), ConfigurationGroupKey(entry.getNode("GroupKey").getValueAsString()));
1483  }
1484  catch(...)
1485  {}
1486 
1487  //on failure, here
1488 
1489  if(progressBar) progressBar->step();
1490 
1491  return std::pair<std::string, ConfigurationGroupKey>("",ConfigurationGroupKey());
1492 }
1493 
1494 //==============================================================================
1495 // map<alias , pair<group name, ConfigurationGroupKey> >
1496 std::map<std::string, std::pair<std::string, ConfigurationGroupKey> > ConfigurationManager::getGroupAliasesConfiguration(void)
1497 {
1498  restoreActiveConfigurationGroups(); //make sure the active configuration backbone is loaded!
1499  //loadConfigurationBackbone();
1500 
1501  std::map<std::string /*alias*/,
1502  std::pair<std::string /*group name*/, ConfigurationGroupKey> > retMap;
1503 
1504  std::vector<std::pair<std::string,ConfigurationTree> > entries = getNode("GroupAliasesConfiguration").getChildren();
1505  for(auto &entryPair: entries)
1506  {
1507  retMap[entryPair.first] = std::pair<std::string, ConfigurationGroupKey>(
1508  entryPair.second.getNode("GroupName").getValueAsString(),
1509  ConfigurationGroupKey(entryPair.second.getNode("GroupKey").getValueAsString()));
1510 
1511  }
1512  return retMap;
1513 }
1514 
1515 //==============================================================================
1516 //getActiveVersions
1517 std::map<std::string, ConfigurationVersion> ConfigurationManager::getActiveVersions(void) const
1518 {
1519  std::map<std::string, ConfigurationVersion> retMap;
1520  for(auto &config:nameToConfigurationMap_)
1521  {
1522  //__COUT__ << config.first << std::endl;
1523 
1524  //check configuration pointer is not null and that there is an active view
1525  if(config.second && config.second->isActive())
1526  {
1527  //__COUT__ << config.first << "_v" << config.second->getViewVersion() << std::endl;
1528  retMap.insert(std::pair<std::string, ConfigurationVersion>(config.first, config.second->getViewVersion()));
1529  }
1530  }
1531  return retMap;
1532 }
1533 
1535 //const DACStream& ConfigurationManager::getDACStream(std::string fecName)
1536 //{
1537 //
1538 // //fixme/todo this is called before setupAll so it breaks!
1539 // //====================================================
1540 // const DetectorConfiguration* detectorConfiguration = __GET_CONFIG__(DetectorConfiguration);
1541 // for(auto& type : detectorConfiguration->getDetectorTypes())
1542 // theDACsConfigurations_[type] = (DACsConfigurationBase*)(getConfigurationByName(type + "DACsConfiguration"));
1543 // //====================================================
1544 //
1545 // theDACStreams_[fecName].makeStream(fecName,
1546 // __GET_CONFIG__(DetectorConfiguration),
1547 // __GET_CONFIG__(DetectorToFEConfiguration),
1548 // theDACsConfigurations_,
1549 // __GET_CONFIG__(MaskConfiguration));//, theTrimConfiguration_);
1550 //
1551 // __COUT__ << "Done with DAC stream!" << std::endl;
1552 // return theDACStreams_[fecName];
1553 //}
1554 
1555 //==============================================================================
1556 std::shared_ptr<ConfigurationGroupKey> ConfigurationManager::makeTheConfigurationGroupKey(ConfigurationGroupKey key)
1557 {
1558  if(theConfigurationGroupKey_)
1559  {
1560  if(*theConfigurationGroupKey_ != key)
1561  destroyConfigurationGroup();
1562  else
1563  return theConfigurationGroupKey_;
1564  }
1565  return std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(key));
1566 }
1567 
1568 //==============================================================================
1569 std::string ConfigurationManager::encodeURIComponent(const std::string &sourceStr)
1570 {
1571  std::string retStr = "";
1572  char encodeStr[4];
1573  for(const auto &c:sourceStr)
1574  if(
1575  (c >= 'a' && c <= 'z') ||
1576  (c >= 'A' && c <= 'Z') ||
1577  (c >= '0' && c <= '9') )
1578  retStr += c;
1579  else
1580  {
1581  sprintf(encodeStr,"%%%2.2X",c);
1582  retStr += encodeStr;
1583  }
1584  return retStr;
1585 }
1586 
1587 //==============================================================================
1588 const std::set<std::string>& ConfigurationManager::getContextMemberNames()
1589 { return ConfigurationManager::contextMemberNames_; }
1590 //==============================================================================
1591 const std::set<std::string>& ConfigurationManager::getBackboneMemberNames()
1592 { return ConfigurationManager::backboneMemberNames_; }
1593 //==============================================================================
1594 const std::set<std::string>& ConfigurationManager::getIterateMemberNames()
1595 { return ConfigurationManager::iterateMemberNames_; }
1596 
1597 
1598 
1599 
1600 
1601 
1602 
1603 
1604 
1605