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