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