otsdaq  v2_03_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/ProgressBar/ProgressBar.h"
4 
5 #include <fstream> // std::ofstream
6 
7 #include "otsdaq-core/TableCore/TableGroupKey.h"
8 
9 using namespace ots;
10 
11 #undef __MF_SUBJECT__
12 #define __MF_SUBJECT__ "ConfigurationManager"
13 
14 const std::string ConfigurationManager::READONLY_USER = "READONLY_USER";
15 
16 const std::string ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME = "XDAQContextTable";
17 const std::string ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME =
18  "XDAQApplicationTable";
19 const std::string ConfigurationManager::GROUP_ALIASES_TABLE_NAME = "GroupAliasesTable";
20 const std::string ConfigurationManager::VERSION_ALIASES_TABLE_NAME =
21  "VersionAliasesTable";
22 
23 // added env check for otsdaq_flatten_active_to_version to function
24 const std::string ConfigurationManager::ACTIVE_GROUPS_FILENAME =
25  ((getenv("SERVICE_DATA_PATH") == NULL)
26  ? (std::string(getenv("USER_DATA")) + "/ServiceData")
27  : (std::string(getenv("SERVICE_DATA_PATH")))) +
28  "/ActiveTableGroups.cfg";
29 const std::string ConfigurationManager::ALIAS_VERSION_PREAMBLE = "ALIAS:";
30 const std::string ConfigurationManager::SCRATCH_VERSION_ALIAS = "Scratch";
31 
32 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT = "Context";
33 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE = "Backbone";
34 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE = "Iterate";
35 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION = "Configuration";
36 const std::string ConfigurationManager::ACTIVE_GROUP_NAME_UNKNOWN = "Unknown";
37 
38 const uint8_t ConfigurationManager::METADATA_COL_ALIASES = 1;
39 const uint8_t ConfigurationManager::METADATA_COL_COMMENT = 2;
40 const uint8_t ConfigurationManager::METADATA_COL_AUTHOR = 3;
41 const uint8_t ConfigurationManager::METADATA_COL_TIMESTAMP = 4;
42 
43 const std::set<std::string> ConfigurationManager::contextMemberNames_ = {
44  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME,
45  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
46  "XDAQApplicationPropertyTable",
47  "DesktopIconTable",
48  "MessageFacilityTable",
49  "GatewaySupervisorTable",
50  "StateMachineTable",
51  "DesktopWindowParameterTable"};
52 const std::set<std::string> ConfigurationManager::backboneMemberNames_ = {
53  ConfigurationManager::GROUP_ALIASES_TABLE_NAME,
54  ConfigurationManager::VERSION_ALIASES_TABLE_NAME};
55 const std::set<std::string> ConfigurationManager::iterateMemberNames_ = {
56  "IterateTable",
57  "IterationPlanTable",
58  "IterationTargetTable",
59  /*command specific tables*/ "IterationCommandBeginLabelTable",
60  "IterationCommandChooseFSMTable",
61  "IterationCommandConfigureAliasTable",
62  "IterationCommandConfigureGroupTable",
63  "IterationCommandExecuteFEMacroTable",
64  "IterationCommandExecuteMacroTable",
65  "IterationCommandMacroDimensionalLoopTable",
66  "IterationCommandMacroDimensionalLoopParameterTable",
67  "IterationCommandModifyGroupTable",
68  "IterationCommandRepeatLabelTable",
69  "IterationCommandRunTable"};
70 
71 //==============================================================================
72 ConfigurationManager::ConfigurationManager()
73  : username_(ConfigurationManager::READONLY_USER)
74  , theInterface_(0)
75  , theConfigurationTableGroupKey_(0)
76  , theContextTableGroupKey_(0)
77  , theBackboneTableGroupKey_(0)
78  , theConfigurationTableGroup_("")
79  , theContextTableGroup_("")
80  , theBackboneTableGroup_("")
81 {
82  theInterface_ = ConfigurationInterface::getInstance(false); // false to use artdaq DB
83  // NOTE: in ConfigurationManagerRW using false currently.. think about consistency!
84  // FIXME
85 
86  // initialize special group metadata table
87  {
88  // Note: "TableGroupMetadata" should never be in conflict
89  // because all other tables end in "...Table"
90 
91  // This is a table called TableGroupMetadata
92  // with 4 fields:
93  // - GroupAliases
94  // - GroupAuthor
95  // - GroupCreationTime
96  // - CommentDescription
97 
98  groupMetadataTable_.setTableName(
99  ConfigurationInterface::GROUP_METADATA_TABLE_NAME);
100  std::vector<TableViewColumnInfo>* colInfo =
101  groupMetadataTable_.getMockupViewP()->getColumnsInfoP();
102 
103  colInfo->push_back(TableViewColumnInfo(
104  TableViewColumnInfo::TYPE_UID, // just to make init() happy
105  "UnusedUID",
106  "UNUSED_UID",
107  TableViewColumnInfo::DATATYPE_NUMBER,
108  "",
109  0));
110  colInfo->push_back(TableViewColumnInfo(TableViewColumnInfo::TYPE_DATA,
111  "GroupAliases",
112  "GROUP_ALIASES",
113  TableViewColumnInfo::DATATYPE_STRING,
114  "",
115  0));
116  colInfo->push_back(TableViewColumnInfo(
117  TableViewColumnInfo::TYPE_COMMENT, // just to make init() happy
118  "CommentDescription",
119  "COMMENT_DESCRIPTION",
120  TableViewColumnInfo::DATATYPE_STRING,
121  "",
122  0));
123  colInfo->push_back(TableViewColumnInfo(
124  TableViewColumnInfo::TYPE_AUTHOR, // just to make init() happy
125  "GroupAuthor",
126  "AUTHOR",
127  TableViewColumnInfo::DATATYPE_STRING,
128  "",
129  0));
130  colInfo->push_back(TableViewColumnInfo(TableViewColumnInfo::TYPE_TIMESTAMP,
131  "GroupCreationTime",
132  "GROUP_CREATION_TIME",
133  TableViewColumnInfo::DATATYPE_TIME,
134  "",
135  0));
136  auto tmpVersion = groupMetadataTable_.createTemporaryView();
137  groupMetadataTable_.setActiveView(tmpVersion);
138  // only need this one and only row for all time
139  groupMetadataTable_.getViewP()->addRow();
140  }
141 
142  init();
143 } // end constructor()
144 
145 //==============================================================================
146 ConfigurationManager::ConfigurationManager(const std::string& username)
148 {
149  username_ = username;
150 } // end constructor(username)
151 
152 //==============================================================================
153 ConfigurationManager::~ConfigurationManager() { destroy(); }
154 
155 //==============================================================================
156 // init
157 // if accumulatedErrors is not null.. fill it with errors
158 // else throw errors (but do not ask restoreActiveTableGroups to throw errors)
159 void ConfigurationManager::init(std::string* accumulatedErrors)
160 {
161  if(accumulatedErrors)
162  *accumulatedErrors = "";
163 
164  // destroy();
165 
166  // once Interface is false (using artdaq db) .. then can cTableGroupce_->getMode() ==
167  // false)
168  {
169  try
170  {
171  restoreActiveTableGroups(accumulatedErrors ? true : false);
172  }
173  catch(std::runtime_error& e)
174  {
175  if(accumulatedErrors)
176  *accumulatedErrors = e.what();
177  else
178  throw;
179  }
180  }
181 } // end init()
182 
183 //==============================================================================
184 // restoreActiveTableGroups
185 // load the active groups from file
186 // Note: this should be used by the Supervisor to maintain
187 // the same configurationGroups surviving software system restarts
188 void ConfigurationManager::restoreActiveTableGroups(
189  bool throwErrors, const std::string& pathToActiveGroupsFile)
190 {
191  destroyTableGroup("", true); // deactivate all
192 
193  std::string fn =
194  pathToActiveGroupsFile == "" ? ACTIVE_GROUPS_FILENAME : pathToActiveGroupsFile;
195  FILE* fp = fopen(fn.c_str(), "r");
196 
197  __COUT__ << "ACTIVE_GROUPS_FILENAME = " << fn << __E__;
198  __COUT__ << "ARTDAQ_DATABASE_URI = " << std::string(getenv("ARTDAQ_DATABASE_URI"))
199  << __E__;
200 
201  if(!fp)
202  {
203  __COUT_WARN__ << "No active groups file found at " << fn << __E__;
204  return;
205  }
206 
207  //__COUT__ << "throwErrors: " << throwErrors << __E__;
208 
209  char tmp[500];
210  char strVal[500];
211 
212  std::string groupName;
213  std::string errorStr = "";
214  bool skip;
215 
216  __SS__;
217 
218  while(fgets(tmp, 500, fp)) // for(int i=0;i<4;++i)
219  {
220  // fgets(tmp,500,fp);
221 
222  skip = false;
223  sscanf(tmp, "%s", strVal); // sscanf to remove '\n'
224  for(unsigned int j = 0; j < strlen(strVal); ++j)
225  if(!((strVal[j] >= 'a' && strVal[j] <= 'z') ||
226  (strVal[j] >= 'A' && strVal[j] <= 'Z') ||
227  (strVal[j] >= '0' && strVal[j] <= '9')))
228  {
229  strVal[j] = '\0';
230  __COUT_INFO__ << "Illegal character found, so skipping!" << __E__;
231 
232  skip = true;
233  break;
234  }
235 
236  if(skip)
237  continue;
238 
239  groupName = strVal;
240  fgets(tmp, 500, fp);
241  sscanf(tmp, "%s", strVal); // sscanf to remove '\n'
242 
243  for(unsigned int j = 0; j < strlen(strVal); ++j)
244  if(!((strVal[j] >= '0' && strVal[j] <= '9')))
245  {
246  strVal[j] = '\0';
247 
248  if(groupName.size() > 3) // notify if seems like a real group name
249  __COUT_INFO__
250  << "Skipping active group with illegal character in name."
251  << __E__;
252 
253  skip = true;
254  break;
255  }
256 
257  if(skip)
258  continue;
259 
260  try
261  {
262  TableGroupKey::getFullGroupString(groupName, TableGroupKey(strVal));
263  }
264  catch(...)
265  {
266  __COUT__ << "illegal group according to TableGroupKey::getFullGroupString..."
267  << __E__;
268  skip = true;
269  }
270 
271  if(skip)
272  continue;
273 
274  try
275  {
276  // load and doActivate
277  loadTableGroup(groupName, TableGroupKey(strVal), true);
278  }
279  catch(std::runtime_error& e)
280  {
281  ss << "Failed to load group in ConfigurationManager::init() with name '"
282  << groupName << "(" << strVal << ")'" << __E__;
283  ss << e.what() << __E__;
284 
285  errorStr += ss.str();
286  }
287  catch(...)
288  {
289  ss << "Failed to load group in ConfigurationManager::init() with name '"
290  << groupName << "(" << strVal << ")'" << __E__;
291 
292  errorStr += ss.str();
293  }
294  }
295 
296  fclose(fp);
297 
298  if(throwErrors && errorStr != "")
299  {
300  __COUT_INFO__ << "\n" << ss.str();
301  __THROW__(errorStr);
302  }
303  else if(errorStr != "")
304  __COUT_INFO__ << "\n" << ss.str();
305 
306 } // end restoreActiveTableGroups()
307 
308 //==============================================================================
309 // destroyTableGroup
310 // destroy all if theGroup == ""
311 // else destroy that group
312 // if onlyDeactivate, then don't delete, just deactivate view
313 void ConfigurationManager::destroyTableGroup(const std::string& theGroup,
314  bool onlyDeactivate)
315 {
316  // delete
317  bool isContext = theGroup == "" || theGroup == theContextTableGroup_;
318  bool isBackbone = theGroup == "" || theGroup == theBackboneTableGroup_;
319  bool isIterate = theGroup == "" || theGroup == theIterateTableGroup_;
320  bool isConfiguration = theGroup == "" || theGroup == theConfigurationTableGroup_;
321 
322  if(!isContext && !isBackbone && !isIterate && !isConfiguration)
323  {
324  __SS__ << "Invalid configuration group to destroy: " << theGroup << __E__;
325  __COUT_ERR__ << ss.str();
326  __SS_THROW__;
327  }
328 
329  std::string dbgHeader = onlyDeactivate ? "Deactivating" : "Destroying";
330  if(theGroup != "")
331  {
332  if(isContext)
333  __COUT__ << dbgHeader << " Context group: " << theGroup << __E__;
334  if(isBackbone)
335  __COUT__ << dbgHeader << " Backbone group: " << theGroup << __E__;
336  if(isIterate)
337  __COUT__ << dbgHeader << " Iterate group: " << theGroup << __E__;
338  if(isConfiguration)
339  __COUT__ << dbgHeader << " Configuration group: " << theGroup << __E__;
340  }
341 
342  std::set<std::string>::const_iterator contextFindIt, backboneFindIt, iterateFindIt;
343  for(auto it = nameToTableMap_.begin(); it != nameToTableMap_.end();
344  /*no increment*/)
345  {
346  contextFindIt = contextMemberNames_.find(it->first);
347  backboneFindIt = backboneMemberNames_.find(it->first);
348  iterateFindIt = iterateMemberNames_.find(it->first);
349  if(theGroup == "" ||
350  ((isContext && contextFindIt != contextMemberNames_.end()) ||
351  (isBackbone && backboneFindIt != backboneMemberNames_.end()) ||
352  (isIterate && iterateFindIt != iterateMemberNames_.end()) ||
353  (!isContext && !isBackbone && contextFindIt == contextMemberNames_.end() &&
354  backboneFindIt == backboneMemberNames_.end() &&
355  iterateFindIt == iterateMemberNames_.end())))
356  {
357  //__COUT__ << "\t" << it->first << __E__;
358  // if(it->second->isActive())
359  // __COUT__ << "\t\t..._v" << it->second->getViewVersion() << __E__;
360 
361  if(onlyDeactivate) // only deactivate
362  {
363  it->second->deactivate();
364  ++it;
365  }
366  else // else, delete/erase
367  {
368  delete it->second;
369  nameToTableMap_.erase(it++);
370  }
371  }
372  else
373  ++it;
374  }
375 
376  if(isConfiguration)
377  {
378  theConfigurationTableGroup_ = "";
379  if(theConfigurationTableGroupKey_ != 0)
380  {
381  __COUT__ << "Destroying Configuration Key: "
382  << *theConfigurationTableGroupKey_ << __E__;
383  theConfigurationTableGroupKey_.reset();
384  }
385 
386  // theDACStreams_.clear();
387  }
388  if(isBackbone)
389  {
390  theBackboneTableGroup_ = "";
391  if(theBackboneTableGroupKey_ != 0)
392  {
393  __COUT__ << "Destroying Backbone Key: " << *theBackboneTableGroupKey_
394  << __E__;
395  theBackboneTableGroupKey_.reset();
396  }
397  }
398  if(isIterate)
399  {
400  theIterateTableGroup_ = "";
401  if(theIterateTableGroupKey_ != 0)
402  {
403  __COUT__ << "Destroying Iterate Key: " << *theIterateTableGroupKey_ << __E__;
404  theIterateTableGroupKey_.reset();
405  }
406  }
407  if(isContext)
408  {
409  theContextTableGroup_ = "";
410  if(theContextTableGroupKey_ != 0)
411  {
412  __COUT__ << "Destroying Context Key: " << *theContextTableGroupKey_ << __E__;
413  theContextTableGroupKey_.reset();
414  }
415  }
416 }
417 
418 //==============================================================================
419 void ConfigurationManager::destroy(void)
420 {
421  // NOTE: Moved to ConfigurationGUISupervisor [FIXME is this correct?? should we use
422  // shared_ptr??]
423  // if( ConfigurationInterface::getInstance(true) != 0 )
424  // delete theInterface_;
425  destroyTableGroup();
426 }
427 
428 //==============================================================================
429 // convertGroupTypeIdToName
430 // return translation:
431 // 0 for context
432 // 1 for backbone
433 // 2 for configuration (others)
434 const std::string& ConfigurationManager::convertGroupTypeIdToName(int groupTypeId)
435 {
436  return groupTypeId == CONTEXT_TYPE
437  ? ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT
438  : (groupTypeId == BACKBONE_TYPE
439  ? ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE
440  : (groupTypeId == ITERATE_TYPE
441  ? ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE
442  : ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION));
443 }
444 
445 //==============================================================================
446 // getTypeOfGroup
447 // return
448 // CONTEXT_TYPE for context
449 // BACKBONE_TYPE for backbone
450 // ITERATE_TYPE for iterate
451 // CONFIGURATION_TYPE for configuration (others)
452 int ConfigurationManager::getTypeOfGroup(
453  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap)
454 {
455  bool isContext = true;
456  bool isBackbone = true;
457  bool isIterate = true;
458  bool inGroup;
459  bool inContext = false;
460  bool inBackbone = false;
461  bool inIterate = false;
462  unsigned int matchCount = 0;
463 
464  for(auto& memberPair : memberMap)
465  {
466  //__COUT__ << "Member name: = "<< memberPair.first << __E__;
468  inGroup = false; // check context
469  for(auto& contextMemberString : contextMemberNames_)
470  if(memberPair.first == contextMemberString)
471  {
472  inGroup = true;
473  inContext = true;
474  ++matchCount;
475  break;
476  }
477  if(!inGroup)
478  {
479  isContext = false;
480  if(inContext) // there was a member in context!
481  {
482  __SS__ << "This group is an incomplete match to a Context group.\n";
483  __COUT_ERR__ << "\n" << ss.str();
484  ss << "\nTo be a Context group, the members must exactly match "
485  << "the following members:\n";
486  int i = 0;
487  for(const auto& memberName : contextMemberNames_)
488  ss << ++i << ". " << memberName << "\n";
489  ss << "\nThe members are as follows::\n";
490  i = 0;
491  for(const auto& memberPairTmp : memberMap)
492  ss << ++i << ". " << memberPairTmp.first << "\n";
493  __SS_THROW__;
494  }
495  }
496 
498  inGroup = false; // check backbone
499  for(auto& backboneMemberString : backboneMemberNames_)
500  if(memberPair.first == backboneMemberString)
501  {
502  inGroup = true;
503  inBackbone = true;
504  ++matchCount;
505  break;
506  }
507  if(!inGroup)
508  {
509  isBackbone = false;
510  if(inBackbone) // there was a member in backbone!
511  {
512  __SS__ << "This group is an incomplete match to a Backbone group.\n";
513  __COUT_ERR__ << "\n" << ss.str();
514  ss << "\nTo be a Backbone group, the members must exactly match "
515  << "the following members:\n";
516  int i = 0;
517  for(auto& memberName : backboneMemberNames_)
518  ss << ++i << ". " << memberName << "\n";
519  ss << "\nThe members are as follows::\n";
520  i = 0;
521  for(const auto& memberPairTmp : memberMap)
522  ss << ++i << ". " << memberPairTmp.first << "\n";
523  //__COUT_ERR__ << "\n" << ss.str();
524  __SS_THROW__;
525  }
526  }
527 
529  inGroup = false; // check iterate
530  for(auto& iterateMemberString : iterateMemberNames_)
531  if(memberPair.first == iterateMemberString)
532  {
533  inGroup = true;
534  inIterate = true;
535  ++matchCount;
536  break;
537  }
538  if(!inGroup)
539  {
540  isIterate = false;
541  if(inIterate) // there was a member in iterate!
542  {
543  __SS__ << "This group is an incomplete match to a Iterate group.\n";
544  __COUT_ERR__ << "\n" << ss.str();
545  ss << "\nTo be a Iterate group, the members must exactly match "
546  << "the following members:\n";
547  int i = 0;
548  for(auto& memberName : iterateMemberNames_)
549  ss << ++i << ". " << memberName << "\n";
550  ss << "\nThe members are as follows::\n";
551  i = 0;
552  for(const auto& memberPairTmp : memberMap)
553  ss << ++i << ". " << memberPairTmp.first << "\n";
554  //__COUT_ERR__ << "\n" << ss.str();
555  __SS_THROW__;
556  }
557  }
558  }
559 
560  if(isContext && matchCount != contextMemberNames_.size())
561  {
562  __SS__ << "This group is an incomplete match to a Context group: "
563  << " Size=" << matchCount << " but should be "
564  << contextMemberNames_.size() << __E__;
565  __COUT_ERR__ << "\n" << ss.str();
566  ss << "\nThe members currently are...\n";
567  int i = 0;
568  for(auto& memberPair : memberMap)
569  ss << ++i << ". " << memberPair.first << "\n";
570  ss << "\nThe expected Context members are...\n";
571  i = 0;
572  for(auto& memberName : contextMemberNames_)
573  ss << ++i << ". " << memberName << "\n";
574  //__COUT_ERR__ << "\n" << ss.str();
575  __SS_THROW__;
576  }
577 
578  if(isBackbone && matchCount != backboneMemberNames_.size())
579  {
580  __SS__ << "This group is an incomplete match to a Backbone group: "
581  << " Size=" << matchCount << " but should be "
582  << backboneMemberNames_.size() << __E__;
583  __COUT_ERR__ << "\n" << ss.str();
584  ss << "\nThe members currently are...\n";
585  int i = 0;
586  for(auto& memberPair : memberMap)
587  ss << ++i << ". " << memberPair.first << "\n";
588  ss << "\nThe expected Backbone members are...\n";
589  i = 0;
590  for(auto& memberName : backboneMemberNames_)
591  ss << ++i << ". " << memberName << "\n";
592  //__COUT_ERR__ << "\n" << ss.str();
593  __SS_THROW__;
594  }
595 
596  if(isIterate && matchCount != iterateMemberNames_.size())
597  {
598  __SS__ << "This group is an incomplete match to a Iterate group: "
599  << " Size=" << matchCount << " but should be "
600  << backboneMemberNames_.size() << __E__;
601  __COUT_ERR__ << "\n" << ss.str();
602  ss << "\nThe members currently are...\n";
603  int i = 0;
604  for(auto& memberPair : memberMap)
605  ss << ++i << ". " << memberPair.first << "\n";
606  ss << "\nThe expected Iterate members are...\n";
607  i = 0;
608  for(auto& memberName : iterateMemberNames_)
609  ss << ++i << ". " << memberName << "\n";
610  //__COUT_ERR__ << "\n" << ss.str();
611  __SS_THROW__;
612  }
613 
614  return isContext ? CONTEXT_TYPE
615  : (isBackbone ? BACKBONE_TYPE
616  : (isIterate ? ITERATE_TYPE : CONFIGURATION_TYPE));
617 }
618 
619 //==============================================================================
620 // getTypeNameOfGroup
621 // return string for group type
622 const std::string& ConfigurationManager::getTypeNameOfGroup(
623  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap)
624 {
625  return convertGroupTypeIdToName(getTypeOfGroup(memberMap));
626 }
627 
628 //==============================================================================
629 // loadMemberMap
630 // loads tables given by name/version pairs in memberMap
631 // Note: does not activate them.
632 //
633 // if filePath == "", then output to cout
634 void ConfigurationManager::dumpActiveConfiguration(const std::string& filePath,
635  const std::string& dumpType)
636 {
637  time_t rawtime = time(0);
638  __COUT__ << "filePath = " << filePath << __E__;
639  __COUT__ << "dumpType = " << dumpType << __E__;
640 
641  std::ofstream fs;
642  fs.open(filePath, std::fstream::out | std::fstream::trunc);
643 
644  std::ostream* out;
645 
646  // if file was valid use it, else default to cout
647  if(fs.is_open())
648  out = &fs;
649  else
650  {
651  if(filePath != "")
652  {
653  __SS__ << "Invalid file path to dump active configuration. File " << filePath
654  << " could not be opened!" << __E__;
655  __COUT_ERR__ << ss.str();
656  __SS_THROW__;
657  }
658  out = &(std::cout);
659  }
660 
661  (*out) << "#################################" << __E__;
662  (*out) << "This is an ots configuration dump.\n\n" << __E__;
663  (*out) << "Source database is $ARTDAQ_DATABASE_URI = \t"
664  << getenv("ARTDAQ_DATABASE_URI") << __E__;
665  (*out) << "\nOriginal location of dump: \t" << filePath << __E__;
666  (*out) << "Type of dump: \t" << dumpType << __E__;
667  (*out) << "Linux time for dump: \t" << rawtime << __E__;
668 
669  {
670  struct tm* timeinfo = localtime(&rawtime);
671  char buffer[100];
672  strftime(buffer, 100, "%c %Z", timeinfo);
673  (*out) << "Display time for dump: \t" << buffer << __E__;
674  }
675 
676  // define local "lambda" functions
677  // active groups
678  // active tables
679  // active group members
680  // active table contents
681 
682  auto localDumpActiveGroups = [](const ConfigurationManager* cfgMgr,
683  std::ostream* out) {
684  std::map<std::string, std::pair<std::string, TableGroupKey>> activeGroups =
685  cfgMgr->getActiveTableGroups();
686 
687  (*out) << "\n\n************************" << __E__;
688  (*out) << "Active Groups:" << __E__;
689  for(auto& group : activeGroups)
690  {
691  (*out) << "\t" << group.first << " := " << group.second.first << " ("
692  << group.second.second << ")" << __E__;
693  }
694  };
695 
696  auto localDumpActiveTables = [](const ConfigurationManager* cfgMgr,
697  std::ostream* out) {
698  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
699 
700  (*out) << "\n\n************************" << __E__;
701  (*out) << "Active Tables:" << __E__;
702  (*out) << "Active Tables count = " << activeTables.size() << __E__;
703 
704  unsigned int i = 0;
705  for(auto& table : activeTables)
706  {
707  (*out) << "\t" << ++i << ". " << table.first << "-v" << table.second << __E__;
708  }
709  };
710 
711  auto localDumpActiveGroupMembers = [](ConfigurationManager* cfgMgr,
712  std::ostream* out) {
713  std::map<std::string, std::pair<std::string, TableGroupKey>> activeGroups =
714  cfgMgr->getActiveTableGroups();
715  (*out) << "\n\n************************" << __E__;
716  (*out) << "Active Group Members:" << __E__;
717  int tableCount = 0;
718  for(auto& group : activeGroups)
719  {
720  (*out) << "\t" << group.first << " := " << group.second.first << " ("
721  << group.second.second << ")" << __E__;
722 
723  if(group.second.first == "")
724  {
725  (*out) << "\t"
726  << "Empty group name. Assuming no active group." << __E__;
727  continue;
728  }
729 
730  std::map<std::string /*name*/, TableVersion /*version*/> memberMap;
731  std::map<std::string /*name*/, std::string /*alias*/> groupAliases;
732  std::string groupComment;
733  std::string groupAuthor;
734  std::string groupCreateTime;
735  time_t groupCreateTime_t;
736 
737  cfgMgr->loadTableGroup(group.second.first,
738  group.second.second,
739  false /*doActivate*/,
740  &memberMap /*memberMap*/,
741  0 /*progressBar*/,
742  0 /*accumulateErrors*/,
743  &groupComment,
744  &groupAuthor,
745  &groupCreateTime,
746  true /*doNotLoadMember*/,
747  0 /*groupTypeString*/,
748  &groupAliases);
749 
750  (*out) << "\t\tGroup Comment: \t" << groupComment << __E__;
751  (*out) << "\t\tGroup Author: \t" << groupAuthor << __E__;
752 
753  sscanf(groupCreateTime.c_str(), "%ld", &groupCreateTime_t);
754  (*out) << "\t\tGroup Create Time: \t" << ctime(&groupCreateTime_t) << __E__;
755  (*out) << "\t\tGroup Aliases: \t" << StringMacros::mapToString(groupAliases)
756  << __E__;
757 
758  (*out) << "\t\tMember table count = " << memberMap.size() << __E__;
759  tableCount += memberMap.size();
760 
761  unsigned int i = 0;
762  for(auto& member : memberMap)
763  {
764  (*out) << "\t\t\t" << ++i << ". " << member.first << "-v" << member.second
765  << __E__;
766  }
767  }
768  (*out) << "\nActive Group Members total table count = " << tableCount << __E__;
769  };
770 
771  auto localDumpActiveTableContents = [](const ConfigurationManager* cfgMgr,
772  std::ostream* out) {
773  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
774 
775  (*out) << "\n\n************************" << __E__;
776  (*out) << "Active Table Contents (table count = " << activeTables.size()
777  << "):" << __E__;
778  unsigned int i = 0;
779  for(auto& table : activeTables)
780  {
781  (*out) << "\n\n=============================================================="
782  "================"
783  << __E__;
784  (*out) << "=================================================================="
785  "============"
786  << __E__;
787  (*out) << "\t" << ++i << ". " << table.first << "-v" << table.second << __E__;
788 
789  cfgMgr->nameToTableMap_.find(table.first)->second->print(*out);
790  }
791  };
792 
793  if(dumpType == "GroupKeys")
794  {
795  localDumpActiveGroups(this, out);
796  }
797  else if(dumpType == "TableVersions")
798  {
799  localDumpActiveTables(this, out);
800  }
801  else if(dumpType == "GroupKeysAndTableVersions")
802  {
803  localDumpActiveGroups(this, out);
804  localDumpActiveTables(this, out);
805  }
806  else if(dumpType == "All")
807  {
808  localDumpActiveGroups(this, out);
809  localDumpActiveGroupMembers(this, out);
810  localDumpActiveTables(this, out);
811  localDumpActiveTableContents(this, out);
812  }
813  else
814  {
815  __SS__
816  << "Invalid dump type '" << dumpType
817  << "' given during dumpActiveConfiguration(). Valid types are as follows:\n"
818  <<
819 
820  // List all choices
821  "GroupKeys"
822  << ", "
823  << "TableVersions"
824  << ", "
825  << "GroupsKeysAndTableVersions"
826  << ", "
827  << "All"
828  <<
829 
830  "\n\nPlease change the State Machine configuration to a valid dump type."
831  << __E__;
832  __SS_THROW__;
833  }
834 
835  if(fs.is_open())
836  fs.close();
837 }
838 
839 //==============================================================================
840 // loadMemberMap
841 // loads tables given by name/version pairs in memberMap
842 // Note: does not activate them.
843 void ConfigurationManager::loadMemberMap(
844  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap)
845 {
846  TableBase* tmpConfigBasePtr;
847  // for each member
848  // get()
849  for(auto& memberPair : memberMap)
850  {
851  //__COUT__ << "\tMember config " << memberPair.first << ":" <<
852  // memberPair.second << __E__;
853 
854  // get the proper temporary pointer
855  // use 0 if doesn't exist yet.
856  // Note: do not want to give nameToTableMap_[memberPair.first]
857  // in case there is failure in get... (exceptions may be thrown)
858  // Note: Default constructor is called by Map, i.e.
859  // nameToTableMap_[memberPair.first] = 0; //create pointer and set to 0
860  tmpConfigBasePtr = 0;
861  if(nameToTableMap_.find(memberPair.first) != nameToTableMap_.end())
862  tmpConfigBasePtr = nameToTableMap_[memberPair.first];
863 
864  theInterface_->get(tmpConfigBasePtr, // configurationPtr
865  memberPair.first, // tableName
866  0, // groupKey
867  0, // groupName
868  false, // dontFill=false to fill
869  memberPair.second, // version
870  false // resetTable
871  );
872 
873  nameToTableMap_[memberPair.first] = tmpConfigBasePtr;
874  if(nameToTableMap_[memberPair.first]->getViewP())
875  {
876  //__COUT__ << "\t\tActivated version: " <<
877  // nameToTableMap_[memberPair.first]->getViewVersion() << __E__;
878  }
879  else
880  {
881  __SS__ << nameToTableMap_[memberPair.first]->getTableName()
882  << ": View version not activated properly!";
883  __SS_THROW__;
884  }
885  }
886 } // end loadMemberMap()
887 
888 //==============================================================================
889 // loadTableGroup
890 // load all members of configuration group
891 // if doActivate
892 // DOES set theConfigurationTableGroup_, theContextTableGroup_, or
893 // theBackboneTableGroup_ on success this also happens with
894 // ConfigurationManagerRW::activateTableGroup for each member
895 // configBase->init()
896 //
897 // if progressBar != 0, then do step handling, for finer granularity
898 //
899 // if(doNotLoadMember) return memberMap; //this is useful if just getting group metadata
900 // else NOTE: active views are changed! (when loading member map)
901 //
902 // throws exception on failure.
903 // map<name , TableVersion >
904 void ConfigurationManager::loadTableGroup(
905  const std::string& groupName,
906  TableGroupKey groupKey,
907  bool doActivate /*=false*/,
908  std::map<std::string, TableVersion>* groupMembers,
909  ProgressBar* progressBar,
910  std::string* accumulatedTreeErrors,
911  std::string* groupComment,
912  std::string* groupAuthor,
913  std::string* groupCreateTime,
914  bool doNotLoadMember /*=false*/,
915  std::string* groupTypeString,
916  std::map<std::string /*name*/, std::string /*alias*/>* groupAliases) try
917 {
918  // clear to defaults
919  if(groupComment)
920  *groupComment = "NO COMMENT FOUND";
921  if(groupAuthor)
922  *groupAuthor = "NO AUTHOR FOUND";
923  if(groupCreateTime)
924  *groupCreateTime = "0";
925  if(groupTypeString)
926  *groupTypeString = "UNKNOWN";
927 
928  // if(groupName == "defaultConfig")
929  // { //debug active versions
930  // std::map<std::string, TableVersion> allActivePairs = getActiveVersions();
931  // for(auto& activePair: allActivePairs)
932  // {
933  // __COUT__ << "Active table = " <<
934  // activePair.first << "-v" <<
935  // getTableByName(activePair.first)->getView().getVersion() <<
936  // __E__;
937  // }
938  // }
939 
940  // load all members of configuration group
941  // if doActivate
942  // determine the type configuration
943  // deactivate all of that type (invalidate active view)
944  //
945  // for each member
946  // get()
947  // if doActivate, configBase->init()
948  //
949  // if doActivate
950  // set theConfigurationTableGroup_, theContextTableGroup_, or
951  // theBackboneTableGroup_ on success
952 
953  // __COUT_INFO__ << "Loading Table Group: " << groupName <<
954  // "(" << groupKey << ")" << __E__;
955 
956  std::map<std::string /*name*/, TableVersion /*version*/> memberMap =
957  theInterface_->getTableGroupMembers(
958  TableGroupKey::getFullGroupString(groupName, groupKey),
959  true /*include meta data table*/);
960  std::map<std::string /*name*/, std::string /*alias*/> aliasMap;
961 
962  if(progressBar)
963  progressBar->step();
964 
965  // remove meta data table and extract info
966  auto metaTablePair = memberMap.find(groupMetadataTable_.getTableName());
967  if(metaTablePair != memberMap.end())
968  {
969  //__COUT__ << "Found group meta data. v" << metaTablePair->second << __E__;
970 
971  memberMap.erase(metaTablePair); // remove from member map that is returned
972 
973  // clear table
974  while(groupMetadataTable_.getView().getNumberOfRows())
975  groupMetadataTable_.getViewP()->deleteRow(0);
976 
977  // retrieve metadata from database
978  try
979  {
980  theInterface_->fill(&groupMetadataTable_, metaTablePair->second);
981  }
982  catch(const std::runtime_error& e)
983  {
984  __COUT_WARN__ << "Ignoring metadata error: " << e.what() << __E__;
985  }
986  catch(...)
987  {
988  __COUT_WARN__ << "Ignoring unknown metadata error. " << __E__;
989  }
990 
991  // check that there is only 1 row
992  if(groupMetadataTable_.getView().getNumberOfRows() != 1)
993  {
994  if(groupMembers)
995  *groupMembers = memberMap; // copy for return
996 
997  groupMetadataTable_.print();
998  __SS__ << "Ignoring that groupMetadataTable_ has wrong number of rows! Must "
999  "be 1. Going with anonymous defaults."
1000  << __E__;
1001  __COUT_ERR__ << "\n" << ss.str();
1002 
1003  // fix metadata table
1004  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
1005  groupMetadataTable_.getViewP()->deleteRow(0);
1006  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
1007  groupMetadataTable_.getViewP()->addRow();
1008 
1009  if(groupComment)
1010  *groupComment = "NO COMMENT FOUND";
1011  if(groupAuthor)
1012  *groupAuthor = "NO AUTHOR FOUND";
1013  if(groupCreateTime)
1014  *groupCreateTime = "0";
1015 
1016  int groupType = -1;
1017  if(groupTypeString) // do before exit case
1018  {
1019  groupType = getTypeOfGroup(memberMap);
1020  *groupTypeString = convertGroupTypeIdToName(groupType);
1021  }
1022  return; // memberMap;
1023  }
1024 
1025  // groupMetadataTable_.print();
1026 
1027  // extract fields
1028  StringMacros::getMapFromString(groupMetadataTable_.getView().getValueAsString(
1029  0, ConfigurationManager::METADATA_COL_ALIASES),
1030  aliasMap);
1031  if(groupAliases)
1032  *groupAliases = aliasMap;
1033  if(groupComment)
1034  *groupComment = groupMetadataTable_.getView().getValueAsString(
1035  0, ConfigurationManager::METADATA_COL_COMMENT);
1036  if(groupAuthor)
1037  *groupAuthor = groupMetadataTable_.getView().getValueAsString(
1038  0, ConfigurationManager::METADATA_COL_AUTHOR);
1039  if(groupCreateTime)
1040  *groupCreateTime = groupMetadataTable_.getView().getValueAsString(
1041  0, ConfigurationManager::METADATA_COL_TIMESTAMP);
1042 
1043  // modify members based on aliases
1044  {
1045  std::map<std::string /*table*/, std::map<std::string /*alias*/, TableVersion>>
1046  versionAliases;
1047  if(aliasMap.size()) // load version aliases
1048  {
1049  __COUTV__(StringMacros::mapToString(aliasMap));
1050  versionAliases = ConfigurationManager::getVersionAliases();
1051  __COUTV__(StringMacros::mapToString(versionAliases));
1052  }
1053 
1054  // convert alias to version
1055  for(auto& aliasPair : aliasMap)
1056  {
1057  // check for alias table in member names
1058  if(memberMap.find(aliasPair.first) != memberMap.end())
1059  {
1060  __COUT__ << "Group member '" << aliasPair.first
1061  << "' was found in group member map!" << __E__;
1062  __COUT__ << "Looking for alias '" << aliasPair.second
1063  << "' in active version aliases..." << __E__;
1064 
1065  if(versionAliases.find(aliasPair.first) == versionAliases.end() ||
1066  versionAliases[aliasPair.first].find(aliasPair.second) ==
1067  versionAliases[aliasPair.first].end())
1068  {
1069  __SS__ << "Group '" << groupName << "(" << groupKey
1070  << ")' requires table version alias '" << aliasPair.first
1071  << ":" << aliasPair.second
1072  << ",' which was not found in the active Backbone!"
1073  << __E__;
1074  __SS_THROW__;
1075  }
1076 
1077  memberMap[aliasPair.first] =
1078  versionAliases[aliasPair.first][aliasPair.second];
1079  __COUT__ << "Version alias translated to " << aliasPair.first
1080  << __E__;
1081  }
1082  }
1083  }
1084  }
1085 
1086  if(groupMembers)
1087  *groupMembers = memberMap; // copy map for return
1088 
1089  if(progressBar)
1090  progressBar->step();
1091 
1092  //__COUT__ << "memberMap loaded size = " << memberMap.size() << __E__;
1093 
1094  int groupType = -1;
1095  try
1096  {
1097  if(groupTypeString) // do before exit case
1098  {
1099  groupType = getTypeOfGroup(memberMap);
1100  *groupTypeString = convertGroupTypeIdToName(groupType);
1101  }
1102 
1103  // if(groupName == "defaultConfig")
1104  // { //debug active versions
1105  // std::map<std::string, TableVersion> allActivePairs =
1106  // getActiveVersions(); for(auto& activePair: allActivePairs)
1107  // {
1108  // __COUT__ << "Active table = " <<
1109  // activePair.first << "-v" <<
1110  // getTableByName(activePair.first)->getView().getVersion()
1111  //<< __E__;
1112  // }
1113  // }
1114 
1115  if(doNotLoadMember)
1116  return; // memberMap; //this is useful if just getting group metadata
1117 
1118  // if not already done, determine the type configuration group
1119  if(!groupTypeString)
1120  groupType = getTypeOfGroup(memberMap);
1121 
1122  if(doActivate)
1123  __COUT__ << "------------------------------------- init start \t [for all "
1124  "plug-ins in "
1125  << convertGroupTypeIdToName(groupType) << " group '" << groupName
1126  << "(" << groupKey << ")"
1127  << "']" << __E__;
1128 
1129  if(doActivate)
1130  {
1131  std::string groupToDeactivate =
1132  groupType == ConfigurationManager::CONTEXT_TYPE
1133  ? theContextTableGroup_
1134  : (groupType == ConfigurationManager::BACKBONE_TYPE
1135  ? theBackboneTableGroup_
1136  : (groupType == ConfigurationManager::ITERATE_TYPE
1137  ? theIterateTableGroup_
1138  : theConfigurationTableGroup_));
1139 
1140  // deactivate all of that type (invalidate active view)
1141  if(groupToDeactivate != "") // deactivate only if pre-existing group
1142  {
1143  //__COUT__ << "groupToDeactivate '" << groupToDeactivate << "'" <<
1144  // __E__;
1145  destroyTableGroup(groupToDeactivate, true);
1146  }
1147  // else
1148  // {
1149  // //Getting here, is kind of strange:
1150  // // - this group may have only been partially loaded before?
1151  // }
1152  }
1153  // if(groupName == "defaultConfig")
1154  // { //debug active versions
1155  // std::map<std::string, TableVersion> allActivePairs =
1156  // getActiveVersions(); for(auto& activePair: allActivePairs)
1157  // {
1158  // __COUT__ << "Active table = " <<
1159  // activePair.first << "-v" <<
1160  // getTableByName(activePair.first)->getView().getVersion()
1161  //<< __E__;
1162  // }
1163  // }
1164 
1165  if(progressBar)
1166  progressBar->step();
1167 
1168  //__COUT__ << "Activating chosen group:" << __E__;
1169 
1170  loadMemberMap(memberMap);
1171 
1172  if(progressBar)
1173  progressBar->step();
1174 
1175  if(accumulatedTreeErrors)
1176  {
1177  //__COUT__ << "Checking chosen group for tree errors..." << __E__;
1178 
1179  getChildren(&memberMap, accumulatedTreeErrors);
1180  if(*accumulatedTreeErrors != "")
1181  {
1182  __COUT_ERR__ << "Errors detected while loading Table Group: " << groupName
1183  << "(" << groupKey << "). Aborting." << __E__;
1184  return; // memberMap; //return member name map to version
1185  }
1186  }
1187 
1188  if(progressBar)
1189  progressBar->step();
1190 
1191  // for each member
1192  // if doActivate, configBase->init()
1193  if(doActivate)
1194  for(auto& memberPair : memberMap)
1195  {
1196  // do NOT allow activating Scratch versions if tracking is ON!
1197  if(ConfigurationInterface::isVersionTrackingEnabled() &&
1198  memberPair.second.isScratchVersion())
1199  {
1200  __SS__ << "Error while activating member Table '"
1201  << nameToTableMap_[memberPair.first]->getTableName() << "-v"
1202  << memberPair.second << " for Table Group '" << groupName
1203  << "(" << groupKey
1204  << ")'. When version tracking is enabled, Scratch views"
1205  << " are not allowed! Please only use unique, persistent "
1206  "versions when version tracking is enabled."
1207  << __E__;
1208  __COUT_ERR__ << "\n" << ss.str();
1209  __SS_THROW__;
1210  }
1211 
1212  // attempt to init using the configuration's specific init
1213  // this could be risky user code, try and catch
1214  try
1215  {
1216  nameToTableMap_[memberPair.first]->init(this);
1217  }
1218  catch(std::runtime_error& e)
1219  {
1220  __SS__ << "Error detected calling "
1221  << nameToTableMap_[memberPair.first]->getTableName()
1222  << ".init()!\n\n " << e.what() << __E__;
1223  __SS_THROW__;
1224  }
1225  catch(...)
1226  {
1227  __SS__ << "Unknown Error detected calling "
1228  << nameToTableMap_[memberPair.first]->getTableName()
1229  << ".init()!\n\n " << __E__;
1230  __SS_THROW__;
1231  }
1232  }
1233 
1234  if(progressBar)
1235  progressBar->step();
1236 
1237  // if doActivate
1238  // set theConfigurationTableGroup_, theContextTableGroup_, or
1239  // theBackboneTableGroup_ on
1240  // success
1241 
1242  if(doActivate)
1243  {
1244  if(groupType == ConfigurationManager::CONTEXT_TYPE) //
1245  {
1246  // __COUT_INFO__ << "Type=Context, Group loaded: " <<
1247  // groupName
1248  //<<
1249  // "(" << groupKey << ")" << __E__;
1250  theContextTableGroup_ = groupName;
1251  theContextTableGroupKey_ =
1252  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
1253  }
1254  else if(groupType == ConfigurationManager::BACKBONE_TYPE)
1255  {
1256  // __COUT_INFO__ << "Type=Backbone, Group loaded: " <<
1257  // groupName <<
1258  // "(" << groupKey << ")" << __E__;
1259  theBackboneTableGroup_ = groupName;
1260  theBackboneTableGroupKey_ =
1261  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
1262  }
1263  else if(groupType == ConfigurationManager::ITERATE_TYPE)
1264  {
1265  // __COUT_INFO__ << "Type=Iterate, Group loaded: " <<
1266  // groupName
1267  //<<
1268  // "(" << groupKey << ")" << __E__;
1269  theIterateTableGroup_ = groupName;
1270  theIterateTableGroupKey_ =
1271  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
1272  }
1273  else // is theConfigurationTableGroup_
1274  {
1275  // __COUT_INFO__ << "Type=Configuration, Group loaded: " <<
1276  // groupName <<
1277  // "(" << groupKey << ")" << __E__;
1278  theConfigurationTableGroup_ = groupName;
1279  theConfigurationTableGroupKey_ =
1280  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
1281  }
1282  }
1283 
1284  if(progressBar)
1285  progressBar->step();
1286 
1287  if(doActivate)
1288  __COUT__ << "------------------------------------- init complete \t [for all "
1289  "plug-ins in "
1290  << convertGroupTypeIdToName(groupType) << " group '" << groupName
1291  << "(" << groupKey << ")"
1292  << "']" << __E__;
1293  } // end failed group load try
1294  catch(...)
1295  {
1296  // save group name and key of failed load attempt
1297  lastFailedGroupLoad_[convertGroupTypeIdToName(groupType)] =
1298  std::pair<std::string, TableGroupKey>(groupName, TableGroupKey(groupKey));
1299 
1300  try
1301  {
1302  throw;
1303  }
1304  catch(const std::runtime_error& e)
1305  {
1306  __SS__ << "Error occurred while loading table group '" << groupName << "("
1307  << groupKey << ")': \n"
1308  << e.what() << __E__;
1309  __COUT_WARN__ << ss.str();
1310  if(accumulatedTreeErrors)
1311  *accumulatedTreeErrors += ss.str();
1312  else
1313  __SS_THROW__;
1314  }
1315  catch(...)
1316  {
1317  __SS__ << "An unknown error occurred while loading table group '" << groupName
1318  << "(" << groupKey << ")." << __E__;
1319  __COUT_WARN__ << ss.str();
1320  if(accumulatedTreeErrors)
1321  *accumulatedTreeErrors += ss.str();
1322  else
1323  __SS_THROW__;
1324  }
1325  }
1326 
1327  return;
1328 }
1329 catch(...)
1330 {
1331  // save group name and key of failed load attempt
1332  lastFailedGroupLoad_[ConfigurationManager::ACTIVE_GROUP_NAME_UNKNOWN] =
1333  std::pair<std::string, TableGroupKey>(groupName, TableGroupKey(groupKey));
1334 
1335  try
1336  {
1337  throw;
1338  }
1339  catch(const std::runtime_error& e)
1340  {
1341  __SS__ << "Error occurred while loading table group: " << e.what() << __E__;
1342  __COUT_WARN__ << ss.str();
1343  if(accumulatedTreeErrors)
1344  *accumulatedTreeErrors += ss.str();
1345  else
1346  __SS_THROW__;
1347  }
1348  catch(...)
1349  {
1350  __SS__ << "An unknown error occurred while loading table group." << __E__;
1351  __COUT_WARN__ << ss.str();
1352  if(accumulatedTreeErrors)
1353  *accumulatedTreeErrors += ss.str();
1354  else
1355  __SS_THROW__;
1356  }
1357 } // end loadTableGroup()
1358 
1359 //==============================================================================
1360 // getActiveTableGroups
1361 // get the active table groups map
1362 // map<type, pair <groupName , TableGroupKey> >
1363 //
1364 // Note: invalid TableGroupKey means no active group currently
1365 std::map<std::string, std::pair<std::string, TableGroupKey>>
1366 ConfigurationManager::getActiveTableGroups(void) const
1367 {
1368  // map<type, pair <groupName , TableGroupKey> >
1369  std::map<std::string, std::pair<std::string, TableGroupKey>> retMap;
1370 
1371  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT] =
1372  std::pair<std::string, TableGroupKey>(
1373  theContextTableGroup_,
1374  theContextTableGroupKey_ ? *theContextTableGroupKey_ : TableGroupKey());
1375  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE] =
1376  std::pair<std::string, TableGroupKey>(
1377  theBackboneTableGroup_,
1378  theBackboneTableGroupKey_ ? *theBackboneTableGroupKey_ : TableGroupKey());
1379  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE] =
1380  std::pair<std::string, TableGroupKey>(
1381  theIterateTableGroup_,
1382  theIterateTableGroupKey_ ? *theIterateTableGroupKey_ : TableGroupKey());
1383  retMap[ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION] =
1384  std::pair<std::string, TableGroupKey>(theConfigurationTableGroup_,
1385  theConfigurationTableGroupKey_
1386  ? *theConfigurationTableGroupKey_
1387  : TableGroupKey());
1388  return retMap;
1389 } // end getActiveTableGroups()
1390 
1391 //==============================================================================
1392 const std::string& ConfigurationManager::getActiveGroupName(const std::string& type) const
1393 {
1394  if(type == "" || type == ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
1395  return theConfigurationTableGroup_;
1396  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
1397  return theContextTableGroup_;
1398  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
1399  return theBackboneTableGroup_;
1400  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
1401  return theIterateTableGroup_;
1402 
1403  __SS__ << "Invalid type requested '" << type << "'" << __E__;
1404  __COUT_ERR__ << ss.str();
1405  __SS_THROW__;
1406 }
1407 
1408 //==============================================================================
1409 TableGroupKey ConfigurationManager::getActiveGroupKey(const std::string& type) const
1410 {
1411  if(type == "" || type == ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
1412  return theConfigurationTableGroupKey_ ? *theConfigurationTableGroupKey_
1413  : TableGroupKey();
1414  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
1415  return theContextTableGroupKey_ ? *theContextTableGroupKey_ : TableGroupKey();
1416  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
1417  return theBackboneTableGroupKey_ ? *theBackboneTableGroupKey_ : TableGroupKey();
1418  if(type == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
1419  return theIterateTableGroupKey_ ? *theIterateTableGroupKey_ : TableGroupKey();
1420 
1421  __SS__ << "Invalid type requested '" << type << "'" << __E__;
1422  __COUT_ERR__ << ss.str();
1423  __SS_THROW__;
1424 }
1425 
1426 //==============================================================================
1427 ConfigurationTree ConfigurationManager::getContextNode(
1428  const std::string& contextUID, const std::string& applicationUID) const
1429 {
1430  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
1431  contextUID);
1432 }
1433 
1434 //==============================================================================
1435 ConfigurationTree ConfigurationManager::getSupervisorNode(
1436  const std::string& contextUID, const std::string& applicationUID) const
1437 {
1438  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
1439  contextUID + "/LinkToApplicationTable/" + applicationUID);
1440 }
1441 
1442 //==============================================================================
1443 ConfigurationTree ConfigurationManager::getSupervisorTableNode(
1444  const std::string& contextUID, const std::string& applicationUID) const
1445 {
1446  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
1447  contextUID + "/LinkToApplicationTable/" + applicationUID +
1448  "/LinkToSupervisorTable");
1449 }
1450 
1451 //==============================================================================
1452 ConfigurationTree ConfigurationManager::getNode(const std::string& nodeString,
1453  bool doNotThrowOnBrokenUIDLinks) const
1454 {
1455  //__COUT__ << "nodeString=" << nodeString << " " << nodeString.length() << __E__;
1456 
1457  // get nodeName (in case of / syntax)
1458  if(nodeString.length() < 1)
1459  {
1460  __SS__ << ("Invalid empty node name") << __E__;
1461  __COUT_ERR__ << ss.str();
1462  __SS_THROW__;
1463  }
1464 
1465  // ignore multiple starting slashes
1466  unsigned int startingIndex = 0;
1467  while(startingIndex < nodeString.length() && nodeString[startingIndex] == '/')
1468  ++startingIndex;
1469 
1470  std::string nodeName = nodeString.substr(
1471  startingIndex, nodeString.find('/', startingIndex) - startingIndex);
1472  //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << __E__;
1473  if(nodeName.length() < 1)
1474  {
1475  // return root node
1476  return ConfigurationTree(this, 0);
1477 
1478  // __SS__ << "Invalid node name: " << nodeName << __E__;
1479  // __COUT_ERR__ << ss.str();
1480  // __SS_THROW__;
1481  }
1482 
1483  std::string childPath = nodeString.substr(nodeName.length() + startingIndex);
1484 
1485  //__COUT__ << "childPath=" << childPath << " " << childPath.length() << __E__;
1486 
1487  ConfigurationTree configTree(this, getTableByName(nodeName));
1488 
1489  if(childPath.length() > 1)
1490  return configTree.getNode(childPath, doNotThrowOnBrokenUIDLinks);
1491  else
1492  return configTree;
1493 }
1494 
1495 //==============================================================================
1496 // getFirstPathToNode
1497 std::string ConfigurationManager::getFirstPathToNode(const ConfigurationTree& node,
1498  const std::string& startPath) const
1499 // void ConfigurationManager::getFirstPathToNode(const ConfigurationTree &node, const
1500 // ConfigurationTree &startNode) const
1501 {
1502  std::string path = "/";
1503  return path;
1504 }
1505 
1506 //==============================================================================
1507 // getChildren
1508 // if memberMap is passed then only consider children in the map
1509 //
1510 // if accumulatedTreeErrors is non null, check for disconnects occurs.
1511 // check is 2 levels deep which should get to the links starting at tables.
1512 std::vector<std::pair<std::string, ConfigurationTree>> ConfigurationManager::getChildren(
1513  std::map<std::string, TableVersion>* memberMap,
1514  std::string* accumulatedTreeErrors) const
1515 {
1516  std::vector<std::pair<std::string, ConfigurationTree>> retMap;
1517  if(accumulatedTreeErrors)
1518  *accumulatedTreeErrors = "";
1519 
1520  if(!memberMap || memberMap->empty()) // return all present active members
1521  {
1522  for(auto& configPair : nameToTableMap_)
1523  {
1524  //__COUT__ << configPair.first << " " << (int)(configPair.second?1:0) <<
1525  // __E__;
1526 
1527  if(configPair.second->isActive()) // only consider if active
1528  {
1529  ConfigurationTree newNode(this, configPair.second);
1530 
1531  if(accumulatedTreeErrors) // check for disconnects
1532  {
1533  try
1534  {
1535  std::vector<std::pair<std::string, ConfigurationTree>>
1536  newNodeChildren = newNode.getChildren();
1537  for(auto& newNodeChild : newNodeChildren)
1538  {
1539  std::vector<std::pair<std::string, ConfigurationTree>>
1540  twoDeepChildren = newNodeChild.second.getChildren();
1541 
1542  for(auto& twoDeepChild : twoDeepChildren)
1543  {
1544  //__COUT__ << configPair.first << " " <<
1545  // newNodeChild.first << " " << twoDeepChild.first
1546  // << __E__;
1547  if(twoDeepChild.second.isLinkNode() &&
1548  twoDeepChild.second.isDisconnected() &&
1549  twoDeepChild.second.getDisconnectedTableName() !=
1550  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
1551  *accumulatedTreeErrors +=
1552  "\n\nAt node '" + configPair.first +
1553  "' with entry UID '" + newNodeChild.first +
1554  "' there is a disconnected child node at link "
1555  "column '" +
1556  twoDeepChild.first + "'" +
1557  " that points to table named '" +
1558  twoDeepChild.second.getDisconnectedTableName() +
1559  "' ...";
1560  }
1561  }
1562  }
1563  catch(std::runtime_error& e)
1564  {
1565  *accumulatedTreeErrors +=
1566  "\n\nAt node '" + configPair.first +
1567  "' error detected descending through children:\n" + e.what();
1568  }
1569  }
1570 
1571  retMap.push_back(
1572  std::pair<std::string, ConfigurationTree>(configPair.first, newNode));
1573  }
1574 
1575  //__COUT__ << configPair.first << __E__;
1576  }
1577  }
1578  else // return only members from the member map (they must be present and active!)
1579  {
1580  for(auto& memberPair : *memberMap)
1581  {
1582  auto mapIt = nameToTableMap_.find(memberPair.first);
1583  if(mapIt == nameToTableMap_.end())
1584  {
1585  __SS__ << "Get Children with member map requires a child '"
1586  << memberPair.first << "' that is not present!" << __E__;
1587  __SS_THROW__;
1588  }
1589  if(!(*mapIt).second->isActive())
1590  {
1591  __SS__ << "Get Children with member map requires a child '"
1592  << memberPair.first << "' that is not active!" << __E__;
1593  __SS_THROW__;
1594  }
1595 
1596  ConfigurationTree newNode(this, (*mapIt).second);
1597 
1598  if(accumulatedTreeErrors) // check for disconnects
1599  {
1600  try
1601  {
1602  std::vector<std::pair<std::string, ConfigurationTree>>
1603  newNodeChildren = newNode.getChildren();
1604  for(auto& newNodeChild : newNodeChildren)
1605  {
1606  std::vector<std::pair<std::string, ConfigurationTree>>
1607  twoDeepChildren = newNodeChild.second.getChildren();
1608 
1609  for(auto& twoDeepChild : twoDeepChildren)
1610  {
1611  //__COUT__ << memberPair.first << " " << newNodeChild.first <<
1612  //" " << twoDeepChild.first << __E__;
1613  if(twoDeepChild.second.isLinkNode() &&
1614  twoDeepChild.second.isDisconnected() &&
1615  twoDeepChild.second.getDisconnectedTableName() !=
1616  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
1617  {
1618  *accumulatedTreeErrors +=
1619  "\n\nAt node '" + memberPair.first +
1620  "' with entry UID '" + newNodeChild.first +
1621  "' there is a disconnected child node at link column "
1622  "'" +
1623  twoDeepChild.first + "'" +
1624  " that points to table named '" +
1625  twoDeepChild.second.getDisconnectedTableName() +
1626  "' ...";
1627 
1628  // check if disconnected table is in group, if not
1629  // software error
1630 
1631  bool found = false;
1632  for(auto& searchMemberPair : *memberMap)
1633  if(searchMemberPair.first ==
1634  twoDeepChild.second.getDisconnectedTableName())
1635  {
1636  found = true;
1637  break;
1638  }
1639  if(!found)
1640  *accumulatedTreeErrors +=
1641  std::string(
1642  "\nNote: It may be safe to ignore this "
1643  "error ") +
1644  "since the link's target table " +
1645  twoDeepChild.second.getDisconnectedTableName() +
1646  " is not a member of this group (and may not be "
1647  "loaded yet).";
1648  }
1649  }
1650  }
1651  }
1652  catch(std::runtime_error& e)
1653  {
1654  *accumulatedTreeErrors +=
1655  "\n\nAt node '" + memberPair.first +
1656  "' error detected descending through children:\n" + e.what();
1657  }
1658  }
1659 
1660  retMap.push_back(
1661  std::pair<std::string, ConfigurationTree>(memberPair.first, newNode));
1662  }
1663  }
1664 
1665  return retMap;
1666 }
1667 
1668 //==============================================================================
1669 // getTableByName
1670 // Get read-only pointer to configuration.
1671 // If Read/Write access is needed use ConfigurationManagerWithWriteAccess
1672 // (For general use, Write access should be avoided)
1673 const TableBase* ConfigurationManager::getTableByName(const std::string& tableName) const
1674 {
1675  std::map<std::string, TableBase*>::const_iterator it;
1676  if((it = nameToTableMap_.find(tableName)) == nameToTableMap_.end())
1677  {
1678  __SS__ << "\n\nCan not find configuration named '" << tableName
1679  << "'\n\n\n\nYou need to load the configuration before it can be used."
1680  << " It probably is missing from the member list of the Table "
1681  "Group that was loaded.\n"
1682  << "\nYou may need to enter wiz mode to remedy the situation, use the "
1683  "following:\n"
1684  << "\n\t StartOTS.sh --wiz"
1685  << "\n\n\n\n"
1686  << __E__;
1687 
1688  // prints out too often, so only throw
1689  // if(tableName != TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
1690  // __COUT_WARN__ << "\n" << ss.str();
1691  __SS_ONLY_THROW__;
1692  }
1693  return it->second;
1694 }
1695 
1696 //==============================================================================
1697 // loadConfigurationBackbone
1698 // loads the active backbone configuration group
1699 // returns the active group key that was loaded
1700 TableGroupKey ConfigurationManager::loadConfigurationBackbone()
1701 {
1702  if(!theBackboneTableGroupKey_) // no active backbone
1703  {
1704  __COUT_WARN__ << "getTableGroupKey() Failed! No active backbone currently."
1705  << __E__;
1706  return TableGroupKey();
1707  }
1708 
1709  // may already be loaded, but that's ok, load anyway to be sure
1710  loadTableGroup(theBackboneTableGroup_, *theBackboneTableGroupKey_);
1711 
1712  return *theBackboneTableGroupKey_;
1713 }
1714 
1715 // Getters
1716 //==============================================================================
1717 // getTableGroupKey
1718 // use backbone to determine default key for systemAlias.
1719 // - runType translates to group key alias,
1720 // which maps to a group name and key pair
1721 //
1722 // NOTE: temporary special aliases are also allowed
1723 // with the following format:
1724 // GROUP:<name>:<key>
1725 //
1726 // return INVALID on failure
1727 // else, pair<group name , TableGroupKey>
1728 std::pair<std::string, TableGroupKey> ConfigurationManager::getTableGroupFromAlias(
1729  std::string systemAlias, ProgressBar* progressBar)
1730 {
1731  // steps
1732  // check if special alias
1733  // if so, parse and return name/key
1734  // else, load active backbone
1735  // find runType in Group Aliases table
1736  // return key
1737 
1738  if(progressBar)
1739  progressBar->step();
1740 
1741  if(systemAlias.find("GROUP:") == 0)
1742  {
1743  if(progressBar)
1744  progressBar->step();
1745 
1746  unsigned int i = strlen("GROUP:");
1747  unsigned int j = systemAlias.find(':', i);
1748 
1749  if(progressBar)
1750  progressBar->step();
1751  if(j > i) // success
1752  return std::pair<std::string, TableGroupKey>(
1753  systemAlias.substr(i, j - i), TableGroupKey(systemAlias.substr(j + 1)));
1754  else // failure
1755  return std::pair<std::string, TableGroupKey>("", TableGroupKey());
1756  }
1757 
1758  loadConfigurationBackbone();
1759 
1760  if(progressBar)
1761  progressBar->step();
1762 
1763  try
1764  {
1765  // find runType in Group Aliases table
1766  ConfigurationTree entry =
1767  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getNode(systemAlias);
1768 
1769  if(progressBar)
1770  progressBar->step();
1771 
1772  return std::pair<std::string, TableGroupKey>(
1773  entry.getNode("GroupName").getValueAsString(),
1774  TableGroupKey(entry.getNode("GroupKey").getValueAsString()));
1775  }
1776  catch(...)
1777  {
1778  }
1779 
1780  // on failure, here
1781 
1782  if(progressBar)
1783  progressBar->step();
1784 
1785  return std::pair<std::string, TableGroupKey>("", TableGroupKey());
1786 }
1787 
1788 //==============================================================================
1789 std::map<std::string /*groupAlias*/, std::pair<std::string /*groupName*/, TableGroupKey>>
1790 ConfigurationManager::getActiveGroupAliases(void)
1791 {
1792  restoreActiveTableGroups(); // make sure the active configuration backbone is
1793  // loaded!
1794  // loadConfigurationBackbone();
1795 
1796  std::map<std::string /*groupAlias*/,
1797  std::pair<std::string /*groupName*/, TableGroupKey>>
1798  retMap;
1799 
1800  std::vector<std::pair<std::string, ConfigurationTree>> entries =
1801  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getChildren();
1802  for(auto& entryPair : entries)
1803  {
1804  retMap[entryPair.first] = std::pair<std::string, TableGroupKey>(
1805  entryPair.second.getNode("GroupName").getValueAsString(),
1806  TableGroupKey(entryPair.second.getNode("GroupKey").getValueAsString()));
1807  }
1808  return retMap;
1809 }
1810 
1811 //==============================================================================
1812 // getVersionAliases()
1813 // get version aliases organized by table, for currently active backbone tables
1814 std::map<std::string /*table name*/,
1815  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1816 ConfigurationManager::getVersionAliases(void) const
1817 {
1818  //__COUT__ << "getVersionAliases()" << __E__;
1819 
1820  std::map<std::string /*table name*/,
1821  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1822  retMap;
1823 
1824  std::map<std::string, TableVersion> activeVersions = getActiveVersions();
1825  std::string versionAliasesTableName =
1826  ConfigurationManager::VERSION_ALIASES_TABLE_NAME;
1827  if(activeVersions.find(versionAliasesTableName) == activeVersions.end())
1828  {
1829  __SS__ << "Active version of VersionAliases missing!"
1830  << "Make sure you have a valid active Backbone Group." << __E__;
1831  __COUT_WARN__ << "\n" << ss.str();
1832  return retMap;
1833  }
1834 
1835  __COUT__ << "activeVersions[\"" << versionAliasesTableName
1836  << "\"]=" << activeVersions[versionAliasesTableName] << __E__;
1837 
1838  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
1839  getNode(versionAliasesTableName).getChildren();
1840 
1841  // create map
1842  // add the first of each tableName, versionAlias pair encountered
1843  // ignore any repeats (Note: this also prevents overwriting of Scratch alias)
1844  std::string tableName, versionAlias;
1845  for(auto& aliasNodePair : aliasNodePairs)
1846  {
1847  tableName = aliasNodePair.second.getNode("TableName").getValueAsString();
1848  versionAlias = aliasNodePair.second.getNode("VersionAlias").getValueAsString();
1849 
1850  if(retMap.find(tableName) != retMap.end() &&
1851  retMap[tableName].find(versionAlias) != retMap[tableName].end())
1852  continue; // skip repeats (Note: this also prevents overwriting of Scratch
1853  // alias)
1854 
1855  // else add version to map
1856  retMap[tableName][versionAlias] =
1857  TableVersion(aliasNodePair.second.getNode("Version").getValueAsString());
1858  }
1859 
1860  return retMap;
1861 } // end getVersionAliases()
1862 
1863 //==============================================================================
1864 // getActiveVersions
1865 std::map<std::string, TableVersion> ConfigurationManager::getActiveVersions(void) const
1866 {
1867  std::map<std::string, TableVersion> retMap;
1868  for(auto& config : nameToTableMap_)
1869  {
1870  //__COUT__ << config.first << __E__;
1871 
1872  // check configuration pointer is not null and that there is an active view
1873  if(config.second && config.second->isActive())
1874  {
1875  //__COUT__ << config.first << "_v" << config.second->getViewVersion() <<
1876  // __E__;
1877  retMap.insert(std::pair<std::string, TableVersion>(
1878  config.first, config.second->getViewVersion()));
1879  }
1880  }
1881  return retMap;
1882 }
1883 
1885 // const DACStream& ConfigurationManager::getDACStream(std::string fecName)
1886 //{
1887 //
1888 // //fixme/todo this is called before setupAll so it breaks!
1889 // //====================================================
1890 // const DetectorConfiguration* detectorConfiguration =
1891 //__GET_CONFIG__(DetectorConfiguration); for(auto& type :
1892 // detectorConfiguration->getDetectorTypes()) theDACsConfigurations_[type] =
1893 //(DACsTableBase*)(getTableByName(type + "DACsConfiguration"));
1894 // //====================================================
1895 //
1896 // theDACStreams_[fecName].makeStream(fecName,
1897 // __GET_CONFIG__(DetectorConfiguration),
1898 // __GET_CONFIG__(DetectorToFEConfiguration),
1899 // theDACsConfigurations_,
1900 // __GET_CONFIG__(MaskConfiguration));//, theTrimConfiguration_);
1901 //
1902 // __COUT__ << "Done with DAC stream!" << __E__;
1903 // return theDACStreams_[fecName];
1904 //}
1905 
1906 //==============================================================================
1907 std::shared_ptr<TableGroupKey> ConfigurationManager::makeTheTableGroupKey(
1908  TableGroupKey key)
1909 {
1910  if(theConfigurationTableGroupKey_)
1911  {
1912  if(*theConfigurationTableGroupKey_ != key)
1913  destroyTableGroup();
1914  else
1915  return theConfigurationTableGroupKey_;
1916  }
1917  return std::shared_ptr<TableGroupKey>(new TableGroupKey(key));
1918 }
1919 
1920 //==============================================================================
1921 std::string ConfigurationManager::encodeURIComponent(const std::string& sourceStr)
1922 {
1923  std::string retStr = "";
1924  char encodeStr[4];
1925  for(const auto& c : sourceStr)
1926  if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
1927  retStr += c;
1928  else
1929  {
1930  sprintf(encodeStr, "%%%2.2X", c);
1931  retStr += encodeStr;
1932  }
1933  return retStr;
1934 }
1935 
1936 //==============================================================================
1937 const std::set<std::string>& ConfigurationManager::getContextMemberNames()
1938 {
1939  return ConfigurationManager::contextMemberNames_;
1940 }
1941 //==============================================================================
1942 const std::set<std::string>& ConfigurationManager::getBackboneMemberNames()
1943 {
1944  return ConfigurationManager::backboneMemberNames_;
1945 }
1946 //==============================================================================
1947 const std::set<std::string>& ConfigurationManager::getIterateMemberNames()
1948 {
1949  return ConfigurationManager::iterateMemberNames_;
1950 }