otsdaq  v2_00_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. File path 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  if(doActivate)
938  __COUT__ << "------------------------------------- loadConfigurationGroup start" << std::endl;
939 
940 
941  //if not already done, determine the type configuration group
942  if(!groupTypeString) groupType = getTypeOfGroup(memberMap);
943 
944  if(doActivate)
945  {
946  std::string groupToDeactivate =
947  groupType==CONTEXT_TYPE?theContextGroup_:
948  (groupType==BACKBONE_TYPE?theBackboneGroup_:
949  (groupType==ITERATE_TYPE?
950  theIterateGroup_:theConfigurationGroup_));
951 
952  // deactivate all of that type (invalidate active view)
953  if(groupToDeactivate != "") //deactivate only if pre-existing group
954  {
955  __COUT__ << "groupToDeactivate '" << groupToDeactivate << "'" << std::endl;
956  destroyConfigurationGroup(groupToDeactivate,true);
957  }
958 // else
959 // {
960 // //Getting here, is kind of strange:
961 // // - this group may have only been partially loaded before?
962 // }
963  }
964 // if(configGroupName == "defaultConfig")
965 // { //debug active versions
966 // std::map<std::string, ConfigurationVersion> allActivePairs = getActiveVersions();
967 // for(auto& activePair: allActivePairs)
968 // {
969 // __COUT__ << "Active table = " <<
970 // activePair.first << "-v" <<
971 // getConfigurationByName(activePair.first)->getView().getVersion() << std::endl;
972 // }
973 // }
974 
975  if(progressBar) progressBar->step();
976 
977  //__COUT__ << "Activating chosen group:" << std::endl;
978 
979 
980  loadMemberMap(memberMap);
981 
982  if(progressBar) progressBar->step();
983 
984  if(accumulatedTreeErrors)
985  {
986  __COUT__ << "Checking chosen group for tree errors..." << std::endl;
987 
988  getChildren(&memberMap, accumulatedTreeErrors);
989  if(*accumulatedTreeErrors != "")
990  {
991  __COUT_ERR__ << "Errors detected while loading Configuration Group: " << configGroupName <<
992  "(" << configGroupKey << "). Aborting." << std::endl;
993  return;// memberMap; //return member name map to version
994  }
995  }
996 
997  if(progressBar) progressBar->step();
998 
999  // for each member
1000  // if doActivate, configBase->init()
1001  if(doActivate)
1002  for(auto &memberPair:memberMap)
1003  {
1004  //do NOT allow activating Scratch versions if tracking is ON!
1005  if(ConfigurationInterface::isVersionTrackingEnabled() &&
1006  memberPair.second.isScratchVersion())
1007  {
1008  __SS__ << "Error while activating member Table '" <<
1009  nameToConfigurationMap_[memberPair.first]->getConfigurationName() <<
1010  "-v" << memberPair.second <<
1011  " for Configuration Group '" << configGroupName <<
1012  "(" << configGroupKey << ")'. When version tracking is enabled, Scratch views" <<
1013  " are not allowed! Please only use unique, persistent versions when version tracking is enabled."
1014  << std::endl;
1015  __COUT_ERR__ << "\n" << ss.str();
1016  throw std::runtime_error(ss.str());
1017  }
1018 
1019 
1020  //attempt to init using the configuration's specific init
1021  // this could be risky user code, try and catch
1022  try
1023  {
1024  nameToConfigurationMap_[memberPair.first]->init(this);
1025  }
1026  catch(std::runtime_error& e)
1027  {
1028  __SS__ << "Error detected calling " <<
1029  nameToConfigurationMap_[memberPair.first]->getConfigurationName() <<
1030  ".init()!\n\n " << e.what() << std::endl;
1031  throw std::runtime_error(ss.str());
1032  }
1033  catch(...)
1034  {
1035  __SS__ << "Error detected calling " <<
1036  nameToConfigurationMap_[memberPair.first]->getConfigurationName() <<
1037  ".init()!\n\n " << std::endl;
1038  throw std::runtime_error(ss.str());
1039  }
1040 
1041  }
1042 
1043  if(progressBar) progressBar->step();
1044 
1045 
1046  // if doActivate
1047  // set theConfigurationGroup_, theContextGroup_, or theBackboneGroup_ on success
1048 
1049  if(doActivate)
1050  {
1051  if(groupType == CONTEXT_TYPE) //
1052  {
1053  __COUT_INFO__ << "Type=Context, Group loaded: " << configGroupName <<
1054  "(" << configGroupKey << ")" << std::endl;
1055  theContextGroup_ = configGroupName;
1056  theContextGroupKey_ = std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(configGroupKey));
1057  }
1058  else if(groupType == BACKBONE_TYPE)
1059  {
1060  __COUT_INFO__ << "Type=Backbone, Group loaded: " << configGroupName <<
1061  "(" << configGroupKey << ")" << std::endl;
1062  theBackboneGroup_ = configGroupName;
1063  theBackboneGroupKey_ = std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(configGroupKey));
1064  }
1065  else if(groupType == ITERATE_TYPE)
1066  {
1067  __COUT_INFO__ << "Type=Iterate, Group loaded: " << configGroupName <<
1068  "(" << configGroupKey << ")" << std::endl;
1069  theIterateGroup_ = configGroupName;
1070  theIterateGroupKey_ = std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(configGroupKey));
1071  }
1072  else //is theConfigurationGroup_
1073  {
1074  __COUT_INFO__ << "Type=Configuration, Group loaded: " << configGroupName <<
1075  "(" << configGroupKey << ")" << std::endl;
1076  theConfigurationGroup_ = configGroupName;
1077  theConfigurationGroupKey_ = std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(configGroupKey));
1078  }
1079  }
1080 
1081  if(progressBar) progressBar->step();
1082 
1083  if(doActivate)
1084  __COUT__ << "------------------------------------- loadConfigurationGroup end" << std::endl;
1085 
1086  return;// memberMap;
1087 }
1088 
1089 
1090 //==============================================================================
1091 //setActiveGlobalConfiguration
1092 // get theActiveGlobalConfig_
1093 // map<type, pair <groupName , ConfigurationGroupKey> >
1094 //
1095 // Note: invalid ConfigurationGroupKey means no active group currently
1096 std::map<std::string, std::pair<std::string, ConfigurationGroupKey> > ConfigurationManager::getActiveConfigurationGroups(void) const
1097 {
1098  // map<type, pair <groupName , ConfigurationGroupKey> >
1099  std::map<std::string, std::pair<std::string, ConfigurationGroupKey> > retMap;
1100 
1101  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT] =
1102  std::pair<std::string,ConfigurationGroupKey>(theContextGroup_ ,theContextGroupKey_ ?*theContextGroupKey_ : ConfigurationGroupKey());
1103  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE] =
1104  std::pair<std::string,ConfigurationGroupKey>(theBackboneGroup_ ,theBackboneGroupKey_ ?*theBackboneGroupKey_ : ConfigurationGroupKey());
1105  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE] =
1106  std::pair<std::string,ConfigurationGroupKey>(theIterateGroup_ ,theIterateGroupKey_ ?*theIterateGroupKey_ : ConfigurationGroupKey());
1107  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION] =
1108  std::pair<std::string,ConfigurationGroupKey>(theConfigurationGroup_,theConfigurationGroupKey_?*theConfigurationGroupKey_: ConfigurationGroupKey());
1109  return retMap;
1110 }
1111 
1112 //==============================================================================
1113 const std::string& ConfigurationManager::getActiveGroupName(const std::string& type) const
1114 {
1115  if(type == "" || type == ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
1116  return theConfigurationGroup_;
1117  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
1118  return theContextGroup_;
1119  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
1120  return theBackboneGroup_;
1121  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
1122  return theIterateGroup_;
1123 
1124  __SS__ << "Invalid type requested '" << type << "'" << std::endl;
1125  __COUT_ERR__ << ss.str();
1126  throw std::runtime_error(ss.str());
1127 }
1128 
1129 //==============================================================================
1130 ConfigurationGroupKey ConfigurationManager::getActiveGroupKey(const std::string& type) const
1131 {
1132  if(type == "" || type == ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
1133  return theConfigurationGroupKey_?*theConfigurationGroupKey_: ConfigurationGroupKey();
1134  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
1135  return theContextGroupKey_ ?*theContextGroupKey_ : ConfigurationGroupKey();
1136  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
1137  return theBackboneGroupKey_ ?*theBackboneGroupKey_ : ConfigurationGroupKey();
1138  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
1139  return theIterateGroupKey_ ?*theIterateGroupKey_ : ConfigurationGroupKey();
1140 
1141  __SS__ << "Invalid type requested '" << type << "'" << std::endl;
1142  __COUT_ERR__ << ss.str();
1143  throw std::runtime_error(ss.str());
1144 }
1145 
1146 //==============================================================================
1147 ConfigurationTree ConfigurationManager::getContextNode(
1148  const std::string &contextUID, const std::string &applicationUID) const
1149 {
1150  return getNode(
1151  "/" + getConfigurationByName(XDAQ_CONTEXT_CONFIG_NAME)->getConfigurationName() +
1152  "/" + contextUID);
1153 }
1154 
1155 //==============================================================================
1156 ConfigurationTree ConfigurationManager::getSupervisorNode(
1157  const std::string &contextUID, const std::string &applicationUID) const
1158 {
1159  return getNode(
1160  "/" + getConfigurationByName(XDAQ_CONTEXT_CONFIG_NAME)->getConfigurationName() +
1161  "/" + contextUID +
1162  "/LinkToApplicationConfiguration/" + applicationUID);
1163 }
1164 
1165 //==============================================================================
1166 ConfigurationTree ConfigurationManager::getSupervisorConfigurationNode(
1167  const std::string &contextUID, const std::string &applicationUID) const
1168 {
1169  return getNode(
1170  "/" + getConfigurationByName(XDAQ_CONTEXT_CONFIG_NAME)->getConfigurationName() +
1171  "/" + contextUID +
1172  "/LinkToApplicationConfiguration/" + applicationUID +
1173  "/LinkToSupervisorConfiguration");
1174 }
1175 
1176 //==============================================================================
1177 ConfigurationTree ConfigurationManager::getNode(const std::string& nodeString,
1178  bool doNotThrowOnBrokenUIDLinks) const
1179 {
1180  //__COUT__ << "nodeString=" << nodeString << " " << nodeString.length() << std::endl;
1181 
1182  //get nodeName (in case of / syntax)
1183  if(nodeString.length() < 1)
1184  {
1185  __SS__ << ("Invalid empty node name") << std::endl;
1186  __COUT_ERR__ << ss.str();
1187  throw std::runtime_error(ss.str());
1188  }
1189 
1190  //ignore multiple starting slashes
1191  unsigned int startingIndex = 0;
1192  while(startingIndex < nodeString.length() &&
1193  nodeString[startingIndex] == '/') ++startingIndex;
1194 
1195  std::string nodeName = nodeString.substr(startingIndex, nodeString.find('/',startingIndex)-startingIndex);
1196  //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << std::endl;
1197  if(nodeName.length() < 1)
1198  {
1199  //return root node
1200  return ConfigurationTree(this,0);
1201 
1202  // __SS__ << "Invalid node name: " << nodeName << std::endl;
1203  // __COUT_ERR__ << ss.str();
1204  // throw std::runtime_error(ss.str());
1205  }
1206 
1207  std::string childPath = nodeString.substr(nodeName.length() + startingIndex);
1208 
1209  //__COUT__ << "childPath=" << childPath << " " << childPath.length() << std::endl;
1210 
1211  ConfigurationTree configTree(this, getConfigurationByName(nodeName));
1212 
1213  if(childPath.length() > 1)
1214  return configTree.getNode(childPath,doNotThrowOnBrokenUIDLinks);
1215  else
1216  return configTree;
1217 }
1218 
1219 //==============================================================================
1220 //getFirstPathToNode
1221 std::string ConfigurationManager::getFirstPathToNode(const ConfigurationTree &node, const std::string &startPath) const
1222 //void ConfigurationManager::getFirstPathToNode(const ConfigurationTree &node, const ConfigurationTree &startNode) const
1223 {
1224  std::string path = "/";
1225  return path;
1226 }
1227 
1228 //==============================================================================
1229 //getChildren
1230 // if memberMap is passed then only consider children in the map
1231 //
1232 // if accumulatedTreeErrors is non null, check for disconnects occurs.
1233 // check is 2 levels deep which should get to the links starting at tables.
1234 std::vector<std::pair<std::string,ConfigurationTree> > ConfigurationManager::getChildren(
1235  std::map<std::string, ConfigurationVersion> *memberMap,
1236  std::string *accumulatedTreeErrors) const
1237 {
1238  std::vector<std::pair<std::string,ConfigurationTree> > retMap;
1239  if(accumulatedTreeErrors) *accumulatedTreeErrors = "";
1240 
1241  if(!memberMap || memberMap->empty()) //return all present active members
1242  {
1243  for(auto &configPair:nameToConfigurationMap_)
1244  {
1245  //__COUT__ << configPair.first << " " << (int)(configPair.second?1:0) << std::endl;
1246 
1247  if(configPair.second->isActive()) //only consider if active
1248  {
1249  ConfigurationTree newNode(this, configPair.second);
1250 
1251 
1252  if(accumulatedTreeErrors) //check for disconnects
1253  {
1254  try
1255  {
1256  std::vector<std::pair<std::string,ConfigurationTree> > newNodeChildren =
1257  newNode.getChildren();
1258  for(auto &newNodeChild: newNodeChildren)
1259  {
1260  std::vector<std::pair<std::string,ConfigurationTree> > twoDeepChildren =
1261  newNodeChild.second.getChildren();
1262 
1263  for(auto &twoDeepChild: twoDeepChildren)
1264  {
1265  //__COUT__ << configPair.first << " " << newNodeChild.first << " " <<
1266  // twoDeepChild.first << std::endl;
1267  if(twoDeepChild.second.isLinkNode() &&
1268  twoDeepChild.second.isDisconnected() &&
1269  twoDeepChild.second.getDisconnectedTableName() !=
1270  ViewColumnInfo::DATATYPE_LINK_DEFAULT)
1271  *accumulatedTreeErrors += "\n\nAt node '" +
1272  configPair.first + "' with entry UID '" +
1273  newNodeChild.first + "' there is a disconnected child node at link column '" +
1274  twoDeepChild.first + "'" +
1275  " that points to table named '" +
1276  twoDeepChild.second.getDisconnectedTableName() +
1277  "' ...";
1278  }
1279  }
1280  }
1281  catch(std::runtime_error &e)
1282  {
1283  *accumulatedTreeErrors += "\n\nAt node '" +
1284  configPair.first + "' error detected descending through children:\n" +
1285  e.what();
1286  }
1287  }
1288 
1289  retMap.push_back(std::pair<std::string,ConfigurationTree>(configPair.first,
1290  newNode));
1291  }
1292 
1293  //__COUT__ << configPair.first << std::endl;
1294  }
1295  }
1296  else //return only members from the member map (they must be present and active!)
1297  {
1298 
1299  for(auto &memberPair: *memberMap)
1300  {
1301  auto mapIt = nameToConfigurationMap_.find(memberPair.first);
1302  if(mapIt == nameToConfigurationMap_.end())
1303  {
1304  __SS__ << "Get Children with member map requires a child '" <<
1305  memberPair.first << "' that is not present!" << std::endl;
1306  throw std::runtime_error(ss.str());
1307  }
1308  if(!(*mapIt).second->isActive())
1309  {
1310  __SS__ << "Get Children with member map requires a child '" <<
1311  memberPair.first << "' that is not active!" << std::endl;
1312  throw std::runtime_error(ss.str());
1313  }
1314 
1315  ConfigurationTree newNode(this, (*mapIt).second);
1316 
1317  if(accumulatedTreeErrors) //check for disconnects
1318  {
1319  try
1320  {
1321  std::vector<std::pair<std::string,ConfigurationTree> > newNodeChildren =
1322  newNode.getChildren();
1323  for(auto &newNodeChild: newNodeChildren)
1324  {
1325  std::vector<std::pair<std::string,ConfigurationTree> > twoDeepChildren =
1326  newNodeChild.second.getChildren();
1327 
1328  for(auto &twoDeepChild: twoDeepChildren)
1329  {
1330  //__COUT__ << memberPair.first << " " << newNodeChild.first << " " <<
1331  // twoDeepChild.first << std::endl;
1332  if(twoDeepChild.second.isLinkNode() &&
1333  twoDeepChild.second.isDisconnected() &&
1334  twoDeepChild.second.getDisconnectedTableName() !=
1335  ViewColumnInfo::DATATYPE_LINK_DEFAULT)
1336  {
1337  *accumulatedTreeErrors += "\n\nAt node '" +
1338  memberPair.first + "' with entry UID '" +
1339  newNodeChild.first + "' there is a disconnected child node at link column '" +
1340  twoDeepChild.first + "'" +
1341  " that points to table named '" +
1342  twoDeepChild.second.getDisconnectedTableName() +
1343  "' ...";
1344 
1345  //check if disconnected table is in group, if not software error
1346 
1347  bool found = false;
1348  for(auto &searchMemberPair: *memberMap)
1349  if(searchMemberPair.first ==
1350  twoDeepChild.second.getDisconnectedTableName())
1351  { found = true; break;}
1352  if(!found)
1353  *accumulatedTreeErrors +=
1354  std::string("\nNote: It may be safe to ignore this error ") +
1355  "since the link's target table " +
1356  twoDeepChild.second.getDisconnectedTableName() +
1357  " is not a member of this group (and may not be loaded yet).";
1358  }
1359  }
1360  }
1361  }
1362  catch(std::runtime_error &e)
1363  {
1364  *accumulatedTreeErrors += "\n\nAt node '" +
1365  memberPair.first + "' error detected descending through children:\n" +
1366  e.what();
1367  }
1368  }
1369 
1370  retMap.push_back(std::pair<std::string,ConfigurationTree>(memberPair.first,
1371  newNode));
1372  }
1373  }
1374 
1375  return retMap;
1376 }
1377 
1378 //==============================================================================
1379 //getConfigurationByName
1380 // Get read-only pointer to configuration.
1381 // If Read/Write access is needed use ConfigurationManagerWithWriteAccess
1382 // (For general use, Write access should be avoided)
1383 const ConfigurationBase* ConfigurationManager::getConfigurationByName(const std::string &configurationName) const
1384 {
1385  std::map<std::string, ConfigurationBase*>::const_iterator it;
1386  if((it = nameToConfigurationMap_.find(configurationName)) == nameToConfigurationMap_.end())
1387  {
1388  __SS__ << "\n\nCan not find configuration named '" <<
1389  configurationName <<
1390  "'\n\n\n\nYou need to load the configuration before it can be used." <<
1391  " It probably is missing from the member list of the Configuration Group that was loaded.\n" <<
1392  "\nYou may need to enter wiz mode to remedy the situation, use the following:\n" <<
1393  "\n\t StartOTS.sh --wiz" <<
1394  "\n\n\n\n"
1395  << std::endl;
1396  //prints out too often
1397  //if(configurationName != ViewColumnInfo::DATATYPE_LINK_DEFAULT)
1398  // __COUT_WARN__ << "\n" << ss.str();
1399  throw std::runtime_error(ss.str());
1400  }
1401  return it->second;
1402 }
1403 
1404 //==============================================================================
1405 //loadConfigurationBackbone
1406 // loads the active backbone configuration group
1407 // returns the active group key that was loaded
1408 ConfigurationGroupKey ConfigurationManager::loadConfigurationBackbone()
1409 {
1410  if(!theBackboneGroupKey_) //no active backbone
1411  {
1412  __COUT_WARN__ << "getConfigurationGroupKey() Failed! No active backbone currently." << std::endl;
1413  return ConfigurationGroupKey();
1414  }
1415 
1416  //may already be loaded, but that's ok, load anyway to be sure
1417  loadConfigurationGroup(theBackboneGroup_,*theBackboneGroupKey_);
1418 
1419  return *theBackboneGroupKey_;
1420 }
1421 
1422 
1423 
1424 //Getters
1425 //==============================================================================
1426 //getConfigurationGroupKey
1427 // use backbone to determine default key for systemAlias.
1428 // - runType translates to group key alias,
1429 // which maps to a group name and key pair
1430 //
1431 // NOTE: temporary special aliases are also allowed
1432 // with the following format:
1433 // GROUP:<name>:<key>
1434 //
1435 // return INVALID on failure
1436 // else, pair<group name , ConfigurationGroupKey>
1437 std::pair<std::string, ConfigurationGroupKey> ConfigurationManager::getConfigurationGroupFromAlias(
1438  std::string systemAlias, ProgressBar* progressBar)
1439 {
1440 
1441  //steps
1442  // check if special alias
1443  // if so, parse and return name/key
1444  // else, load active backbone
1445  // find runType in GroupAliasesConfiguration
1446  // return key
1447 
1448  if(progressBar) progressBar->step();
1449 
1450  if(systemAlias.find("GROUP:") == 0)
1451  {
1452  if(progressBar) progressBar->step();
1453 
1454  unsigned int i = strlen("GROUP:");
1455  unsigned int j = systemAlias.find(':',i);
1456 
1457  if(progressBar) progressBar->step();
1458  if(j>i) //success
1459  return std::pair<std::string, ConfigurationGroupKey>(
1460  systemAlias.substr(i,j-i),
1461  ConfigurationGroupKey(systemAlias.substr(j+1)));
1462  else //failure
1463  return std::pair<std::string, ConfigurationGroupKey>("",ConfigurationGroupKey());
1464  }
1465 
1466 
1467  loadConfigurationBackbone();
1468 
1469  if(progressBar) progressBar->step();
1470 
1471  try
1472  {
1473  // find runType in GroupAliasesConfiguration
1474  ConfigurationTree entry = getNode("GroupAliasesConfiguration").getNode(systemAlias);
1475 
1476  if(progressBar) progressBar->step();
1477 
1478  return std::pair<std::string, ConfigurationGroupKey>(entry.getNode("GroupName").getValueAsString(), ConfigurationGroupKey(entry.getNode("GroupKey").getValueAsString()));
1479  }
1480  catch(...)
1481  {}
1482 
1483  //on failure, here
1484 
1485  if(progressBar) progressBar->step();
1486 
1487  return std::pair<std::string, ConfigurationGroupKey>("",ConfigurationGroupKey());
1488 }
1489 
1490 //==============================================================================
1491 // map<alias , pair<group name, ConfigurationGroupKey> >
1492 std::map<std::string, std::pair<std::string, ConfigurationGroupKey> > ConfigurationManager::getGroupAliasesConfiguration(void)
1493 {
1494  restoreActiveConfigurationGroups(); //make sure the active configuration backbone is loaded!
1495  //loadConfigurationBackbone();
1496 
1497  std::map<std::string /*alias*/,
1498  std::pair<std::string /*group name*/, ConfigurationGroupKey> > retMap;
1499 
1500  std::vector<std::pair<std::string,ConfigurationTree> > entries = getNode("GroupAliasesConfiguration").getChildren();
1501  for(auto &entryPair: entries)
1502  {
1503  retMap[entryPair.first] = std::pair<std::string, ConfigurationGroupKey>(
1504  entryPair.second.getNode("GroupName").getValueAsString(),
1505  ConfigurationGroupKey(entryPair.second.getNode("GroupKey").getValueAsString()));
1506 
1507  }
1508  return retMap;
1509 }
1510 
1511 //==============================================================================
1512 //getActiveVersions
1513 std::map<std::string, ConfigurationVersion> ConfigurationManager::getActiveVersions(void) const
1514 {
1515  std::map<std::string, ConfigurationVersion> retMap;
1516  for(auto &config:nameToConfigurationMap_)
1517  {
1518  //__COUT__ << config.first << std::endl;
1519 
1520  //check configuration pointer is not null and that there is an active view
1521  if(config.second && config.second->isActive())
1522  {
1523  //__COUT__ << config.first << "_v" << config.second->getViewVersion() << std::endl;
1524  retMap.insert(std::pair<std::string, ConfigurationVersion>(config.first, config.second->getViewVersion()));
1525  }
1526  }
1527  return retMap;
1528 }
1529 
1531 //const DACStream& ConfigurationManager::getDACStream(std::string fecName)
1532 //{
1533 //
1534 // //fixme/todo this is called before setupAll so it breaks!
1535 // //====================================================
1536 // const DetectorConfiguration* detectorConfiguration = __GET_CONFIG__(DetectorConfiguration);
1537 // for(auto& type : detectorConfiguration->getDetectorTypes())
1538 // theDACsConfigurations_[type] = (DACsConfigurationBase*)(getConfigurationByName(type + "DACsConfiguration"));
1539 // //====================================================
1540 //
1541 // theDACStreams_[fecName].makeStream(fecName,
1542 // __GET_CONFIG__(DetectorConfiguration),
1543 // __GET_CONFIG__(DetectorToFEConfiguration),
1544 // theDACsConfigurations_,
1545 // __GET_CONFIG__(MaskConfiguration));//, theTrimConfiguration_);
1546 //
1547 // __COUT__ << "Done with DAC stream!" << std::endl;
1548 // return theDACStreams_[fecName];
1549 //}
1550 
1551 //==============================================================================
1552 std::shared_ptr<ConfigurationGroupKey> ConfigurationManager::makeTheConfigurationGroupKey(ConfigurationGroupKey key)
1553 {
1554  if(theConfigurationGroupKey_)
1555  {
1556  if(*theConfigurationGroupKey_ != key)
1557  destroyConfigurationGroup();
1558  else
1559  return theConfigurationGroupKey_;
1560  }
1561  return std::shared_ptr<ConfigurationGroupKey>(new ConfigurationGroupKey(key));
1562 }
1563 
1564 //==============================================================================
1565 std::string ConfigurationManager::encodeURIComponent(const std::string &sourceStr)
1566 {
1567  std::string retStr = "";
1568  char encodeStr[4];
1569  for(const auto &c:sourceStr)
1570  if(
1571  (c >= 'a' && c <= 'z') ||
1572  (c >= 'A' && c <= 'Z') ||
1573  (c >= '0' && c <= '9') )
1574  retStr += c;
1575  else
1576  {
1577  sprintf(encodeStr,"%%%2.2X",c);
1578  retStr += encodeStr;
1579  }
1580  return retStr;
1581 }
1582 
1583 //==============================================================================
1584 const std::set<std::string>& ConfigurationManager::getContextMemberNames()
1585 { return ConfigurationManager::contextMemberNames_; }
1586 //==============================================================================
1587 const std::set<std::string>& ConfigurationManager::getBackboneMemberNames()
1588 { return ConfigurationManager::backboneMemberNames_; }
1589 //==============================================================================
1590 const std::set<std::string>& ConfigurationManager::getIterateMemberNames()
1591 { return ConfigurationManager::iterateMemberNames_; }
1592 
1593 
1594 
1595 
1596 
1597 
1598 
1599 
1600 
1601