otsdaq  3.09.00
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 #include "otsdaq/TablePlugins/XDAQContextTable/XDAQContextTable.h"
6 
7 #include <dirent.h> // DIR and dirent
8 #include <fstream> // std::ofstream
9 #include <sstream> // std::istringstream
10 
11 #include "otsdaq/TableCore/TableGroupKey.h"
12 #include "otsdaq/TablePlugins/DesktopIconTable.h" //for dynamic desktop icon change
13 
14 using namespace ots;
15 
16 #undef __MF_SUBJECT__
17 #define __MF_SUBJECT__ "ConfigurationManager"
18 
19 // clang-format off
20 
21 const std::string ConfigurationManager::LAST_TABLE_GROUP_SAVE_PATH = ((getenv("SERVICE_DATA_PATH") == NULL)
22  ? (std::string(__ENV__("USER_DATA")) + "/ServiceData")
23  : (std::string(__ENV__("SERVICE_DATA_PATH")))) +
24  "/RunControlData/";
25 
26 const std::string ConfigurationManager::LAST_ACTIVATED_CONFIG_GROUP_FILE = "CFGLastActivatedConfigGroup.hist";
27 const std::string ConfigurationManager::LAST_ACTIVATED_CONTEXT_GROUP_FILE = "CFGLastActivatedContextGroup.hist";
28 const std::string ConfigurationManager::LAST_ACTIVATED_BACKBONE_GROUP_FILE = "CFGLastActivatedBackboneGroup.hist";
29 const std::string ConfigurationManager::LAST_ACTIVATED_ITERATE_GROUP_FILE = "CFGLastActivatedIterateGroup.hist";
30 
31 const std::string ConfigurationManager::ACTIVATED_CONFIGS_FILE = "CFGActivatedConfigGroups.hist";
32 const std::string ConfigurationManager::ACTIVATED_CONTEXTS_FILE = "CFGActivatedContextGroups.hist";
33 const std::string ConfigurationManager::ACTIVATED_BACKBONES_FILE = "CFGActivatedBackboneGroups.hist";
34 const std::string ConfigurationManager::ACTIVATED_ITERATES_FILE = "CFGActivatedIterateGroups.hist";
35 
36 const std::string ConfigurationManager::LAST_ATTEMPTED_CONFIGURE_CONFIG_ALIAS_FILE = "CFGAttemptedConfigureConfigAlias.hist";
37 const std::string ConfigurationManager::LAST_ATTEMPTED_CONFIGURE_CONFIG_GROUP_FILE = "CFGAttemptedConfigureConfigGroup.hist";
38 
39 const std::string ConfigurationManager::ATTEMPTED_CONFIGURE_CONFIG_ALIASES_FILE = "CFGAttemptedConfigureConfigAliases.hist";
40 const std::string ConfigurationManager::ATTEMPTED_CONFIGURE_CONFIGS_FILE = "CFGAttemptedConfigureConfigGroups.hist";
41 
42 const std::string ConfigurationManager::LAST_CONFIGURED_CONFIG_ALIAS_FILE = "CFGLastConfiguredConfigAlias.hist";
43 const std::string ConfigurationManager::LAST_CONFIGURED_CONFIG_GROUP_FILE = "CFGLastConfiguredConfigGroup.hist";
44 const std::string ConfigurationManager::LAST_CONFIGURED_CONTEXT_GROUP_FILE = "CFGLastConfiguredContextGroup.hist";
45 const std::string ConfigurationManager::LAST_CONFIGURED_BACKBONE_GROUP_FILE = "CFGLastConfiguredBackboneGroup.hist";
46 const std::string ConfigurationManager::LAST_CONFIGURED_ITERATE_GROUP_FILE = "CFGLastConfiguredIterateGroup.hist";
47 
48 const std::string ConfigurationManager::CONFIGURED_CONFIG_ALIASES_FILE = "CFGConfiguredConfigAliases.hist";
49 const std::string ConfigurationManager::CONFIGURED_CONFIGS_FILE = "CFGConfiguredConfigGroups.hist";
50 const std::string ConfigurationManager::CONFIGURED_CONTEXTS_FILE = "CFGConfiguredContextGroups.hist";
51 const std::string ConfigurationManager::CONFIGURED_BACKBONES_FILE = "CFGConfiguredBackboneGroups.hist";
52 const std::string ConfigurationManager::CONFIGURED_ITERATES_FILE = "CFGConfiguredIterateGroups.hist";
53 
54 const std::string ConfigurationManager::LAST_STARTED_CONFIG_ALIAS_FILE = "CFGLastStartedConfigAlias.hist";
55 const std::string ConfigurationManager::LAST_STARTED_CONFIG_GROUP_FILE = "CFGLastStartedConfigGroup.hist";
56 const std::string ConfigurationManager::LAST_STARTED_CONTEXT_GROUP_FILE = "CFGLastStartedContextGroup.hist";
57 const std::string ConfigurationManager::LAST_STARTED_BACKBONE_GROUP_FILE = "CFGLastStartedBackboneGroup.hist";
58 const std::string ConfigurationManager::LAST_STARTED_ITERATE_GROUP_FILE = "CFGLastStartedIterateGroup.hist";
59 
60 const std::string ConfigurationManager::STARTED_CONFIG_ALIASES_FILE = "CFGStartedConfigAliases.hist";
61 const std::string ConfigurationManager::STARTED_CONFIGS_FILE = "CFGStartedConfigGroups.hist";
62 const std::string ConfigurationManager::STARTED_CONTEXTS_FILE = "CFGStartedContextGroups.hist";
63 const std::string ConfigurationManager::STARTED_BACKBONES_FILE = "CFGStartedBackboneGroups.hist";
64 const std::string ConfigurationManager::STARTED_ITERATES_FILE = "CFGStartedIterateGroups.hist";
65 
66 const std::string ConfigurationManager::CONFIGURED_OR_STARTED_CONFIG_ALIASES_FILE = "CFGConfiguredOrStartedConfigAliases.hist";
67 const std::string ConfigurationManager::CONFIGURED_OR_STARTED_CONFIGS_FILE = "CFGConfiguredOrStartedConfigGroups.hist";
68 const std::string ConfigurationManager::CONFIGURED_OR_STARTED_CONTEXTS_FILE = "CFGConfiguredOrStartedContextGroups.hist";
69 const std::string ConfigurationManager::CONFIGURED_OR_STARTED_BACKBONES_FILE = "CFGConfiguredOrStartedBackboneGroups.hist";
70 const std::string ConfigurationManager::CONFIGURED_OR_STARTED_ITERATES_FILE = "CFGConfiguredOrStartedIterateGroups.hist";
71 
72 
73 const std::string ConfigurationManager::READONLY_USER = "READONLY_USER";
74 
75 const std::string ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME = "XDAQContextTable";
76 const std::string ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME = "XDAQApplicationTable";
77 const std::string ConfigurationManager::XDAQ_APP_PROPERTY_TABLE_NAME = "XDAQApplicationPropertyTable";
78 const std::string ConfigurationManager::GROUP_ALIASES_TABLE_NAME = "GroupAliasesTable";
79 const std::string ConfigurationManager::VERSION_ALIASES_TABLE_NAME = "VersionAliasesTable";
80 const std::string ConfigurationManager::ARTDAQ_TOP_TABLE_NAME = "ARTDAQSupervisorTable";
81 const std::string ConfigurationManager::DESKTOP_ICON_TABLE_NAME = "DesktopIconTable";
82 
84 const std::string ConfigurationManager::ACTIVE_GROUPS_FILENAME = ((getenv("SERVICE_DATA_PATH") == NULL)
85  ? (std::string(__ENV__("USER_DATA")) + "/ServiceData")
86  : (std::string(__ENV__("SERVICE_DATA_PATH")))) +
87  "/ActiveTableGroups.cfg";
88 
89 const std::string ConfigurationManager::ALIAS_VERSION_PREAMBLE = "ALIAS:";
90 const std::string ConfigurationManager::SCRATCH_VERSION_ALIAS = "Scratch";
91 const std::string ConfigurationManager::SUBSYSTEM_COMMON_VERSION_ALIAS = "SubsystemCommon";
92 const std::string ConfigurationManager::SUBSYSTEM_COMMON_OVERRIDE_VERSION_ALIAS = "SubsystemCommonOverride";
93 const std::string ConfigurationManager::SUBSYSTEM_COMMON_CONTEXT_VERSION_ALIAS = "SubsystemCommonContext";
94 const std::string ConfigurationManager::SUBSYSTEM_COMMON_CONTEXT_OVERRIDE_VERSION_ALIAS = "SubsystemCommonContextOverride";
95 
96 
97 const std::string ConfigurationManager::GROUP_TYPE_NAME_CONTEXT = "Context";
98 const std::string ConfigurationManager::GROUP_TYPE_NAME_BACKBONE = "Backbone";
99 const std::string ConfigurationManager::GROUP_TYPE_NAME_ITERATE = "Iterate";
100 const std::string ConfigurationManager::GROUP_TYPE_NAME_CONFIGURATION = "Configuration";
101 const std::string ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN = "UNKNOWN";
102 
103 const std::string ConfigurationManager::UNKNOWN_INFO = "UNKNOWN";
104 const std::string ConfigurationManager::UNKNOWN_TIME = "0";
105 
106 const uint8_t ConfigurationManager::METADATA_COL_ALIASES = 1;
107 const uint8_t ConfigurationManager::METADATA_COL_COMMENT = 2;
108 const uint8_t ConfigurationManager::METADATA_COL_AUTHOR = 3;
109 const uint8_t ConfigurationManager::METADATA_COL_TIMESTAMP = 4;
110 
111 const std::string ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE = "SubsystemUserDataPathsTable";
112 
113 
114 const std::set<std::string> ConfigurationManager::fixedContextMemberNames_ = {
115  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME,
116  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME,
117  "XDAQApplicationPropertyTable",
118  ConfigurationManager::DESKTOP_ICON_TABLE_NAME,
119  "MessageFacilityTable",
120  "GatewaySupervisorTable",
121  "StateMachineTable",
122  "DesktopWindowParameterTable",
123  "SlowControlsDashboardSupervisorTable"
124  };
125 const std::set<std::string> ConfigurationManager::backboneMemberNames_ = {
126  ConfigurationManager::GROUP_ALIASES_TABLE_NAME,
127  ConfigurationManager::VERSION_ALIASES_TABLE_NAME
128  };
129 const std::set<std::string> ConfigurationManager::iterateMemberNames_ = {
130  "IterateTable",
131  "IterationPlanTable",
132  "IterationTargetTable",
133  /*command specific tables*/ "IterationCommandBeginLabelTable",
134  "IterationCommandChooseFSMTable",
135  "IterationCommandConfigureAliasTable",
136  "IterationCommandConfigureGroupTable",
137  "IterationCommandExecuteFEMacroTable",
138  "IterationCommandExecuteMacroTable",
139  "IterationCommandMacroDimensionalLoopTable",
140  "IterationCommandMacroDimensionalLoopParameterTable",
141  "IterationCommandModifyGroupTable",
142  "IterationCommandRepeatLabelTable",
143  "IterationCommandRunTable"
144  };
145 
146 // clang-format on
147 
148 //==============================================================================
149 ConfigurationManager::ConfigurationManager(bool initForWriteAccess /*=false*/,
150  bool doInitializeFromFhicl /*=false*/,
151  bool forceNotFirstInContext /*=false*/)
152  : startClockTime_(std::chrono::steady_clock::now())
153  , deltaClockTime_(std::chrono::steady_clock::now())
154  , forceNotFirstInContext_(forceNotFirstInContext)
155  , mfSubject_(ConfigurationManager::READONLY_USER)
156  , username_(ConfigurationManager::READONLY_USER)
157  , theInterface_(0)
158  , theConfigurationTableGroupKey_(0)
159  , theContextTableGroupKey_(0)
160  , theBackboneTableGroupKey_(0)
161  , theConfigurationTableGroup_("")
162  , theContextTableGroup_("")
163  , theBackboneTableGroup_("")
164  , groupMetadataTable_(true /*special table*/, TableBase::GROUP_METADATA_TABLE_NAME)
165 {
166  __GEN_COUTTV__(runTimeSeconds());
167  theInterface_ = ConfigurationInterface::getInstance(
168  ConfigurationInterface::CONFIGURATION_MODE::
169  ARTDAQ_DATABASE); // false to use artdaq DB
170 
171  __GEN_COUTTV__(runTimeSeconds());
172 
173  // // initialize special group metadata table
174  // {
175  // // Note: "TableGroupMetadata" should never be in conflict
176  // // because all other tables end in "...Table"
177 
178  // // This is a table called TableGroupMetadata
179  // // with 4 fields:
180  // // - GroupAliases
181  // // - GroupAuthor
182  // // - GroupCreationTime
183  // // - CommentDescription
184 
185  // groupMetadataTable_.setTableName(
186  // TableBase::GROUP_METADATA_TABLE_NAME);
187  // std::vector<TableViewColumnInfo>* colInfo =
188  // groupMetadataTable_.getMockupViewP()->getColumnsInfoP();
189  // colInfo->push_back(TableViewColumnInfo(
190  // TableViewColumnInfo::TYPE_UID, // just to make init() happy
191  // "UnusedUID",
192  // "UNUSED_UID",
193  // TableViewColumnInfo::DATATYPE_NUMBER,
194  // 0 /*Default*/,
195  // "",
196  // 0 /*Min*/,
197  // 0 /*Max*/,
198  // 0));
199  // colInfo->push_back(TableViewColumnInfo(TableViewColumnInfo::TYPE_DATA,
200  // "GroupAliases",
201  // "GROUP_ALIASES",
202  // TableViewColumnInfo::DATATYPE_STRING,
203  // 0 /*Default*/,
204  // "",
205  // 0 /*Min*/,
206  // 0 /*Max*/,
207  // 0));
208  // colInfo->push_back(TableViewColumnInfo(
209  // TableViewColumnInfo::TYPE_COMMENT, // just to make init() happy
210  // TableViewColumnInfo::COL_NAME_COMMENT,
211  // "COMMENT_DESCRIPTION",
212  // TableViewColumnInfo::DATATYPE_STRING,
213  // 0 /*Default*/,
214  // "",
215  // 0 /*Min*/,
216  // 0 /*Max*/,
217  // 0));
218  // colInfo->push_back(TableViewColumnInfo(
219  // TableViewColumnInfo::TYPE_AUTHOR, // just to make init() happy
220  // "GroupAuthor",
221  // "AUTHOR",
222  // TableViewColumnInfo::DATATYPE_STRING,
223  // 0 /*Default*/,
224  // "",
225  // 0 /*Min*/,
226  // 0 /*Max*/,
227  // 0));
228  // colInfo->push_back(TableViewColumnInfo(TableViewColumnInfo::TYPE_TIMESTAMP,
229  // "GroupCreationTime",
230  // "GROUP_CREATION_TIME",
231  // TableViewColumnInfo::DATATYPE_TIME,
232  // 0 /*Default*/,
233  // "",
234  // 0 /*Min*/,
235  // 0 /*Max*/,
236  // 0));
237  // auto tmpVersion = groupMetadataTable_.createTemporaryView();
238  // groupMetadataTable_.setActiveView(tmpVersion);
239  // // only need this one and only row for all time
240  // groupMetadataTable_.getViewP()->addRow();
241  // }
242 
243  if(doInitializeFromFhicl)
244  {
245  // create tables and fill based on fhicl
246  initializeFromFhicl(__ENV__("CONFIGURATION_INIT_FCL"));
247  return;
248  }
249  // else do normal init
250 
251  __GEN_COUTTV__(runTimeSeconds());
252  if(!initForWriteAccess) //ConfigurationManagerRW can do manual init later when it calls getAllTableInfo(true)
253  init(0 /*accumulatedErrors*/, initForWriteAccess);
254  __GEN_COUTTV__(runTimeSeconds());
255 
256 } // end constructor()
257 
258 //==============================================================================
259 ConfigurationManager::ConfigurationManager(const std::string& username)
260  : ConfigurationManager(true /*initForWriteAccess*/)
261 {
262  __GEN_COUT__ << "Private constructor for write access called." << __E__;
263  // overwrite read-only username initialization with write-access username:
264  mfSubject_ = username;
265  username_ = username;
266 } // end constructor(username)
267 
268 //==============================================================================
269 ConfigurationManager::~ConfigurationManager() { destroy(); }
270 
271 //==============================================================================
277 void ConfigurationManager::init(std::string* accumulatedErrors /*=0*/,
278  bool initForWriteAccess /*= false*/,
279  std::string* accumulatedWarnings /*=0*/)
280 {
281  // if(accumulatedErrors)
282  // *accumulatedErrors = "";
283 
284  // destroy();
285 
286  // once Interface is false (using artdaq db) ..
287  // then can test (configurationInterface_->getMode() == false)
288  {
289  try
290  {
291  __GEN_COUTTV__(username_);
292 
293  // if write access, then load all specified table groups (including configuration group),
294  // otherwise skip configuration group. Important to consider initForWriteAccess
295  // because this may be called before username_ is properly initialized
296  ConfigurationManager::LoadGroupType onlyLoadIfBackboneOrContext =
297  ConfigurationManager::LoadGroupType::ALL_TYPES;
298  if(username_ == ConfigurationManager::READONLY_USER && !initForWriteAccess)
299  onlyLoadIfBackboneOrContext =
300  ConfigurationManager::LoadGroupType::ONLY_BACKBONE_OR_CONTEXT_TYPES;
301 
302  // clang-format off
303  restoreActiveTableGroups(accumulatedErrors ? true : false /*throwErrors*/,
304  "" /*pathToActiveGroupsFile*/,
305  onlyLoadIfBackboneOrContext,
306  accumulatedWarnings);
307  // clang-format on
308  }
309  catch(std::runtime_error& e)
310  {
311  __GEN_COUT_ERR__ << "Error caught in init(): " << e.what();
312  if(accumulatedErrors)
313  *accumulatedErrors += e.what();
314  else
315  {
316  __SS__ << e.what(); // add line number of rethrow
317  __SS_ONLY_THROW__;
318  }
319  }
320  }
321 } // end init()
322 
323 //==============================================================================
329  bool throwErrors /*=false*/,
330  const std::string& pathToActiveGroupsFile /*=""*/,
331  ConfigurationManager::LoadGroupType
332  onlyLoadIfBackboneOrContext /*= ConfigurationManager::LoadGroupType::ALL_TYPES */,
333  std::string* accumulatedWarnings /*=0*/)
334 {
335  destroyTableGroup("", true); // deactivate all
336 
337  std::string fn =
338  pathToActiveGroupsFile == "" ? ACTIVE_GROUPS_FILENAME : pathToActiveGroupsFile;
339  FILE* fp = fopen(fn.c_str(), "r");
340 
341  __GEN_COUTT__ << "ACTIVE_GROUPS_FILENAME = " << fn << __E__;
342  __GEN_COUTS__(10) << "ARTDAQ_DATABASE_URI = "
343  << std::string(__ENV__("ARTDAQ_DATABASE_URI")) << __E__;
344 
345  if(!fp)
346  {
347  __GEN_COUT_WARN__ << "No active groups file found at " << fn << __E__;
348  return;
349  }
350 
351  __GEN_COUTVS__(10, throwErrors);
352 
353  char tmp[500];
354  char strVal[500];
355 
356  std::string groupName;
357  std::string errorStr = "";
358  bool skip;
359 
360  __SS__;
361 
362  while(fgets(tmp, 500, fp))
363  {
364  // do check for out of sync.. i.e. name is a number
365  {
366  int numberCheck = 0;
367  sscanf(tmp, "%d", &numberCheck);
368  if(numberCheck)
369  {
370  __GEN_COUT__
371  << "Out of sync with active groups file lines, attempting to resync."
372  << __E__;
373  continue;
374  }
375  }
376 
377  skip = false;
378  sscanf(tmp, "%s", strVal); // sscanf to remove '\n'
379  for(unsigned int j = 0; j < strlen(strVal); ++j)
380  if(!((strVal[j] >= 'a' && strVal[j] <= 'z') ||
381  (strVal[j] >= 'A' && strVal[j] <= 'Z') ||
382  (strVal[j] >= '0' && strVal[j] <= '9')))
383  {
384  strVal[j] = '\0';
385  if(strlen(strVal) == 0)
386  __GEN_COUT__ << "Empty group name found, so skipping! Check active "
387  "groups file: "
388  << fn << __E__;
389  else
390  __GEN_COUT_WARN__
391  << "Illegal character found in group name '" << strVal
392  << "', so skipping! Check active groups file: " << fn << __E__;
393 
394  skip = true;
395  break;
396  }
397 
398  if(skip)
399  continue;
400 
401  groupName = strVal;
402  fgets(tmp, 500, fp);
403  sscanf(tmp, "%s", strVal); // sscanf to remove '\n'
404 
405  for(unsigned int j = 0; j < strlen(strVal); ++j)
406  if(!((strVal[j] >= '0' && strVal[j] <= '9')))
407  {
408  strVal[j] = '\0';
409 
410  if(groupName.size() > 3) // notify if seems like a real group name
411  __GEN_COUT_WARN__
412  << "Skipping active group with illegal character in group key '"
413  << strVal << ".' Check active groups file: " << fn << __E__;
414 
415  skip = true;
416  break;
417  }
418 
419  if(groupName.size() <= 3)
420  continue; //skip illegal group names
421 
422  if(skip)
423  continue;
424 
425  try
426  {
428  }
429  catch(...)
430  {
431  __GEN_COUT__
432  << "illegal group according to TableGroupKey::getFullGroupString... "
433  "Check active groups file: "
434  << fn << __E__;
435  skip = true;
436  }
437 
438  if(skip)
439  continue;
440 
441  try
442  {
443  // load and doActivate
444  std::string groupAccumulatedErrors = "";
445 
446  if(accumulatedWarnings)
447  __GEN_COUT__ << "Ignoring warnings while loading and activating group '"
448  << groupName << "(" << strVal << ")'" << __E__;
449 
451  groupName,
452  TableGroupKey(strVal),
453  true /*doActivate*/,
454  0 /*groupMembers*/,
455  0 /*progressBar*/,
456  (accumulatedWarnings ? &groupAccumulatedErrors
457  : 0) /*accumulateWarnings = 0*/,
458  0 /*groupComment = 0*/,
459  0 /*groupAuthor = 0*/,
460  0 /*groupCreateTime = 0*/,
461  0 /*doNotLoadMembers = false*/,
462  0 /*groupTypeString = 0*/,
463  0 /*groupAliases = 0*/,
464  onlyLoadIfBackboneOrContext /*onlyLoadIfBackboneOrContext = false*/
465  );
466 
467  if(accumulatedWarnings)
468  *accumulatedWarnings += groupAccumulatedErrors;
469  }
470  catch(std::runtime_error& e)
471  {
472  ss << "Failed to load group in ConfigurationManager::init() with name '"
473  << groupName << "(" << strVal
474  << ")' specified active by active groups file: " << fn << __E__;
475  ss << e.what() << __E__;
476 
477  errorStr += ss.str();
478  }
479  catch(...)
480  {
481  ss << "Failed to load group in ConfigurationManager::init() with name '"
482  << groupName << "(" << strVal
483  << ")' specified active by active groups file: " << fn << __E__;
484  try
485  {
486  throw;
487  } //one more try to printout extra info
488  catch(const std::exception& e)
489  {
490  ss << "Exception message: " << e.what();
491  }
492  catch(...)
493  {
494  }
495  errorStr += ss.str();
496  }
497  }
498 
499  fclose(fp);
500 
501  if(throwErrors && errorStr != "")
502  {
503  __SS__ << "\n" << errorStr;
504  __SS_ONLY_THROW__;
505  }
506  else if(errorStr != "")
507  __GEN_COUT_WARN__ << "\n" << errorStr;
508 
509 } // end restoreActiveTableGroups()
510 
511 //==============================================================================
516 void ConfigurationManager::destroyTableGroup(const std::string& theGroup,
517  bool onlyDeactivate)
518 {
519  // delete
520  bool isContext = theGroup == "" || theGroup == theContextTableGroup_;
521  bool isBackbone = theGroup == "" || theGroup == theBackboneTableGroup_;
522  bool isIterate = theGroup == "" || theGroup == theIterateTableGroup_;
523  bool isConfiguration = theGroup == "" || theGroup == theConfigurationTableGroup_;
524 
525  if(!isContext && !isBackbone && !isIterate && !isConfiguration)
526  {
527  __SS__ << "Invalid configuration group to destroy: " << theGroup << __E__;
528  __GEN_COUT_ERR__ << ss.str();
529  __SS_THROW__;
530  }
531 
532  std::string dbgHeader = onlyDeactivate ? "Deactivating" : "Destroying";
533  if(theGroup != "")
534  {
535  if(isContext)
536  __GEN_COUT__ << dbgHeader << " Context group: " << theGroup << __E__;
537  if(isBackbone)
538  __GEN_COUT__ << dbgHeader << " Backbone group: " << theGroup << __E__;
539  if(isIterate)
540  __GEN_COUT__ << dbgHeader << " Iterate group: " << theGroup << __E__;
541  if(isConfiguration)
542  __GEN_COUT__ << dbgHeader << " Configuration group: " << theGroup << __E__;
543  }
544 
545  getActiveContextMemberNames(); // make sure active contextMemberNames_ are up to date
546 
547  std::set<std::string>::const_iterator contextFindIt, backboneFindIt, iterateFindIt;
548  for(auto it = nameToTableMap_.begin(); it != nameToTableMap_.end();
549  /*no increment*/)
550  {
551  contextFindIt = contextMemberNames_.find(it->first);
552  backboneFindIt = backboneMemberNames_.find(it->first);
553  iterateFindIt = iterateMemberNames_.find(it->first);
554 
555  __GEN_COUTT__ << "Considering table: " << it->first << " contextFindIt:"
556  << (contextFindIt != contextMemberNames_.end() ? "Y" : "N")
557  << " backboneFindIt:"
558  << (backboneFindIt != backboneMemberNames_.end() ? "Y" : "N")
559  << " iterateFindIt:"
560  << (iterateFindIt != iterateMemberNames_.end() ? "Y" : "N")
561  << __E__;
562  if(theGroup == "" ||
563  ((isContext &&
564  contextFindIt !=
565  contextMemberNames_
566  .end()) || //for context group, deactivate context members AND optional member
567  (isContext &&
568  it->first ==
570  CONTEXT_SUBSYSTEM_OPTIONAL_TABLE) || //optional context member
571  (isBackbone && backboneFindIt != backboneMemberNames_.end()) ||
572  (isIterate && iterateFindIt != iterateMemberNames_.end()) ||
573  (isConfiguration && //for configuration group, deactivate all tables not specified in other group types
574  contextFindIt == contextMemberNames_.end() &&
575  it->first != ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE &&
576  backboneFindIt == backboneMemberNames_.end() &&
577  iterateFindIt == iterateMemberNames_.end())))
578  {
579  __GEN_COUTT__ << "\t" << dbgHeader << ".. " << it->first
580  << (it->second->isActive()
581  ? "_v" + it->second->getViewVersion().str()
582  : "")
583  << __E__;
584 
585  if(onlyDeactivate) // only deactivate
586  {
587  it->second->deactivate();
588  ++it;
589  }
590  else // else, delete/erase
591  {
592  delete it->second;
593  nameToTableMap_.erase(it++);
594  }
595  }
596  else
597  ++it;
598  }
599 
600  if(isConfiguration)
601  {
602  theConfigurationTableGroup_ = "";
603  if(theConfigurationTableGroupKey_ != 0)
604  {
605  __GEN_COUTT__ << "Destroying Configuration Key: "
606  << *theConfigurationTableGroupKey_ << __E__;
607  theConfigurationTableGroupKey_.reset();
608  }
609  }
610  if(isBackbone)
611  {
612  theBackboneTableGroup_ = "";
613  if(theBackboneTableGroupKey_ != 0)
614  {
615  __GEN_COUTT__ << "Destroying Backbone Key: " << *theBackboneTableGroupKey_
616  << __E__;
617  theBackboneTableGroupKey_.reset();
618  }
619  }
620  if(isIterate)
621  {
622  theIterateTableGroup_ = "";
623  if(theIterateTableGroupKey_ != 0)
624  {
625  __GEN_COUTT__ << "Destroying Iterate Key: " << *theIterateTableGroupKey_
626  << __E__;
627  theIterateTableGroupKey_.reset();
628  }
629  }
630  if(isContext)
631  {
632  theContextTableGroup_ = "";
633  if(theContextTableGroupKey_ != 0)
634  {
635  __GEN_COUTT__ << "Destroying Context Key: " << *theContextTableGroupKey_
636  << __E__;
637  theContextTableGroupKey_.reset();
638  }
639  }
640 } //end destroyTableGroup()
641 
642 //==============================================================================
643 void ConfigurationManager::destroy(void) { destroyTableGroup(); } //end destroy()
644 
645 //==============================================================================
652  const ConfigurationManager::GroupType& groupTypeId)
653 {
654  return groupTypeId == ConfigurationManager::GroupType::CONTEXT_TYPE
655  ? ConfigurationManager::GROUP_TYPE_NAME_CONTEXT
656  : (groupTypeId == ConfigurationManager::GroupType::BACKBONE_TYPE
657  ? ConfigurationManager::GROUP_TYPE_NAME_BACKBONE
658  : (groupTypeId == ConfigurationManager::GroupType::ITERATE_TYPE
659  ? ConfigurationManager::GROUP_TYPE_NAME_ITERATE
660  : (groupTypeId == ConfigurationManager::GroupType::
661  CONFIGURATION_TYPE
662  ? ConfigurationManager::GROUP_TYPE_NAME_CONFIGURATION
663  : ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN)));
664 } // end convertGroupTypeToName()
665 
666 //==============================================================================
673 ConfigurationManager::GroupType ConfigurationManager::getTypeOfGroup(
674  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap)
675 {
676  bool isContext = true;
677  bool isBackbone = true;
678  bool isIterate = true;
679  bool inGroup;
680  bool inContext = false;
681  bool inBackbone = false;
682  bool inIterate = false;
683  unsigned int matchCount = 0;
684 
685  for(auto& memberPair : memberMap)
686  {
687  //__COUT__ << "Member name: = "<< memberPair.first << __E__;
689  inGroup = false; // check context
690  if(memberPair.first == CONTEXT_SUBSYSTEM_OPTIONAL_TABLE)
691  {
692  inGroup = true;
693  inContext = true;
694  }
695  else
696  for(auto& contextMemberString : fixedContextMemberNames_)
697  if(memberPair.first == contextMemberString)
698  {
699  inGroup = true;
700  inContext = true;
701  ++matchCount;
702  break;
703  }
704  if(!inGroup)
705  {
706  isContext = false;
707  if(inContext) // there was a member in context!
708  {
709  __SS__ << "This group is an incomplete match to a Context group.\n";
710  ss << "\nTo be a Context group, the members must exactly match "
711  << "the following members (w/ or wo/ the optional table "
712  << CONTEXT_SUBSYSTEM_OPTIONAL_TABLE << "):\n";
713  int i = 0;
714  for(const auto& memberName : fixedContextMemberNames_)
715  ss << ++i << ". " << memberName << "\n";
716  ss << "\nThe members are as follows::\n";
717  i = 0;
718  for(const auto& memberPairTmp : memberMap)
719  ss << ++i << ". " << memberPairTmp.first << "\n";
720  __SS_ONLY_THROW__;
721  }
722  }
723 
725  inGroup = false; // check backbone
726  for(auto& backboneMemberString : backboneMemberNames_)
727  if(memberPair.first == backboneMemberString)
728  {
729  inGroup = true;
730  inBackbone = true;
731  ++matchCount;
732  break;
733  }
734  if(!inGroup)
735  {
736  isBackbone = false;
737  if(inBackbone) // there was a member in backbone!
738  {
739  __SS__ << "This group is an incomplete match to a Backbone group.\n";
740  ss << "\nTo be a Backbone group, the members must exactly match "
741  << "the following members:\n";
742  int i = 0;
743  for(auto& memberName : backboneMemberNames_)
744  ss << ++i << ". " << memberName << "\n";
745  ss << "\nThe members are as follows::\n";
746  i = 0;
747  for(const auto& memberPairTmp : memberMap)
748  ss << ++i << ". " << memberPairTmp.first << "\n";
749  //__COUT_ERR__ << "\n" << ss.str();
750  __SS_ONLY_THROW__;
751  }
752  }
753 
755  inGroup = false; // check iterate
756  for(auto& iterateMemberString : iterateMemberNames_)
757  if(memberPair.first == iterateMemberString)
758  {
759  inGroup = true;
760  inIterate = true;
761  ++matchCount;
762  break;
763  }
764  if(!inGroup)
765  {
766  isIterate = false;
767  if(inIterate) // there was a member in iterate!
768  {
769  __SS__ << "This group is an incomplete match to a Iterate group.\n";
770  ss << "\nTo be a Iterate group, the members must exactly match "
771  << "the following members:\n";
772  int i = 0;
773  for(auto& memberName : iterateMemberNames_)
774  ss << ++i << ". " << memberName << "\n";
775  ss << "\nThe members are as follows::\n";
776  i = 0;
777  for(const auto& memberPairTmp : memberMap)
778  ss << ++i << ". " << memberPairTmp.first << "\n";
779  //__COUT_ERR__ << "\n" << ss.str();
780  __SS_ONLY_THROW__;
781  }
782  }
783  }
784 
785  if((isContext || inContext) && matchCount != fixedContextMemberNames_.size())
786  {
787  __SS__ << "This group is an incomplete match to a Context group: "
788  << " Size=" << matchCount << " but should be "
789  << fixedContextMemberNames_.size() << __E__;
790  ss << "\nThe members currently are...\n";
791  int i = 0;
792  for(auto& memberPair : memberMap)
793  ss << ++i << ". " << memberPair.first << "\n";
794  ss << "\nThe expected Context members are...\n";
795  i = 0;
796  for(auto& memberName : fixedContextMemberNames_)
797  ss << ++i << ". " << memberName << "\n";
798  ss << "optional. (" << CONTEXT_SUBSYSTEM_OPTIONAL_TABLE << ")\n";
799  //__COUT_ERR__ << "\n" << ss.str();
800  __SS_ONLY_THROW__;
801  }
802 
803  if((isBackbone || inBackbone) && matchCount != backboneMemberNames_.size())
804  {
805  __SS__ << "This group is an incomplete match to a Backbone group: "
806  << " Size=" << matchCount << " but should be "
807  << backboneMemberNames_.size() << __E__;
808  ss << "\nThe members currently are...\n";
809  int i = 0;
810  for(auto& memberPair : memberMap)
811  ss << ++i << ". " << memberPair.first << "\n";
812  ss << "\nThe expected Backbone members are...\n";
813  i = 0;
814  for(auto& memberName : backboneMemberNames_)
815  ss << ++i << ". " << memberName << "\n";
816  //__COUT_ERR__ << "\n" << ss.str();
817  __SS_ONLY_THROW__;
818  }
819 
820  if((isIterate || inIterate) && matchCount != iterateMemberNames_.size())
821  {
822  __SS__ << "This group is an incomplete match to a Iterate group: "
823  << " Size=" << matchCount << " but should be "
824  << iterateMemberNames_.size() << __E__;
825  ss << "\nThe members currently are...\n";
826  int i = 0;
827  for(auto& memberPair : memberMap)
828  ss << ++i << ". " << memberPair.first << "\n";
829  ss << "\nThe expected Iterate members are...\n";
830  i = 0;
831  for(auto& memberName : iterateMemberNames_)
832  ss << ++i << ". " << memberName << "\n";
833  //__COUT_ERR__ << "\n" << ss.str();
834  __SS_ONLY_THROW__;
835  }
836 
837  return isContext
838  ? ConfigurationManager::GroupType::CONTEXT_TYPE
839  : (isBackbone
840  ? ConfigurationManager::GroupType::BACKBONE_TYPE
841  : (isIterate
842  ? ConfigurationManager::GroupType::ITERATE_TYPE
843  : ConfigurationManager::GroupType::CONFIGURATION_TYPE));
844 } // end getTypeOfGroup()
845 
846 //==============================================================================
850  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap)
851 {
852  return convertGroupTypeToName(getTypeOfGroup(memberMap));
853 } // end getTypeNameOfGroup()
854 
855 //==============================================================================
861 #define OUT out << tabStr << commentStr
862 #define PUSHTAB tabStr += "\t"
863 #define POPTAB tabStr.resize(tabStr.size() - 1)
864 #define PUSHCOMMENT commentStr += "# "
865 #define POPCOMMENT commentStr.resize(commentStr.size() - 2)
866 
867 void ConfigurationManager::dumpMacroMakerModeFhicl()
868 {
869  if(nameToTableMap_.find("FEInterfaceTable") == nameToTableMap_.end())
870  {
871  __COUT__ << "Skipping dumpMacroMakerModeFhicl() since FEInterface table is not "
872  "activated."
873  << __E__;
874  return;
875  }
876 
877  std::string filepath =
878  __ENV__("USER_DATA") + std::string("/") + "MacroMakerModeConfigurations";
879  mkdir(filepath.c_str(), 0755);
880  filepath += "/MacroMakerModeFhiclDump.fcl";
881  __GEN_COUT__ << "dumpMacroMakerModeFhicl: " << filepath << __E__;
882 
884  // generate MacroMaker mode fhicl file
885  std::fstream out;
886 
887  std::string tabStr = "";
888  std::string commentStr = "";
889 
890  out.open(filepath, std::fstream::out | std::fstream::trunc);
891  if(out.fail())
892  {
893  __SS__ << "Failed to open MacroMaker mode fcl file for configuration dump: "
894  << filepath << __E__;
895  __SS_THROW__;
896  }
897 
898  try
899  {
900  std::vector<std::pair<std::string, ConfigurationTree>> fes =
901  getNode("FEInterfaceTable").getChildren();
902 
903  for(auto& fe : fes)
904  {
905  // skip status false
906  if(!fe.second.status())
907  continue;
908 
909  //__GEN_COUTV__(fe.first);
910 
911  OUT << fe.first << ": {" << __E__;
912  PUSHTAB;
913 
914  // only do FEInterfacePluginName and LinkToFETypeTable at top level
915 
916  OUT << "FEInterfacePluginName"
917  << ": \t"
918  << "\"" << fe.second.getNode("FEInterfacePluginName").getValueAsString()
919  << "\"" << __E__;
920 
921  recursiveTreeToFhicl(
922  fe.second.getNode("LinkToFETypeTable"), out, tabStr, commentStr);
923 
924  POPTAB;
925  OUT << "} //end " << fe.first << __E__ << __E__;
926 
927  } // end fe handling
928  }
929  catch(...)
930  {
931  __SS__ << "Failed to complete MacroMaker mode fcl "
932  "file configuration dump due to error."
933  << __E__;
934  try
935  {
936  throw;
937  } //one more try to printout extra info
938  catch(const std::runtime_error& e)
939  {
940  ss << "Exception message: " << e.what();
941  }
942  catch(const std::exception& e)
943  {
944  ss << "Exception message: " << e.what();
945  }
946  __GEN_COUT_ERR__ << ss.str();
947  }
948 
949  out.close();
950  // end fhicl output
951 } // end dumpMacroMakerModeFhicl()
952 
953 //==============================================================================
962 void ConfigurationManager::recursiveTreeToFhicl(ConfigurationTree node,
963  std::ostream& out /* = std::cout */,
964  std::string& tabStr /* = "" */,
965  std::string& commentStr /* = "" */,
966  unsigned int depth /* = -1 */)
967 {
968  if(depth == 0)
969  {
970  __COUT__ << __COUT_HDR_P__ << "Depth limit reached. Ending recursion." << __E__;
971  return;
972  }
973 
974  //__COUT__ << __COUT_HDR_P__ << "Adding tree record '" << node.getValueAsString() << "' fields..." << __E__;
975 
976  if(depth == (unsigned int)-1)
977  depth = 10;
978 
979  // decorate link node with link_table {} wrapper
980  if(node.isLinkNode())
981  {
982  if(node.isDisconnected())
983  {
984  //__COUT__ << node.getFieldName() << " field is a disconnected link." << __E__;
985  return;
986  }
987 
988  OUT << node.getFieldName() << "_"
989  << node.getValueAsString(true /* returnLinkTableValue */) << ": \t{" << __E__;
990  PUSHTAB;
991  } // end link preamble decoration
992 
993  if(node.isGroupLinkNode())
994  {
995  // for group link, handle each as a UID record
996  std::vector<std::pair<std::string, ConfigurationTree>> children =
997  node.getChildren();
998  for(auto& child : children)
999  recursiveTreeToFhicl(child.second, out, tabStr, commentStr, depth - 1);
1000 
1001  POPTAB;
1002  OUT << "} //end " << node.getValueAsString(true /* returnLinkTableValue */)
1003  << " group link record" << __E__;
1004  return;
1005  } // end group link handling
1006 
1007  // treat as UID record now
1008  // give UID decoration, then contents
1009 
1010  // open UID decoration
1011  OUT << node.getValueAsString() << ": \t{" << __E__;
1012  PUSHTAB;
1013  { // open UID content
1014 
1015  std::vector<std::pair<std::string, ConfigurationTree>> fields =
1016  node.getChildren();
1017 
1018  // skip last 3 fields that are always common
1019  for(unsigned int i = 0; i < fields.size() - 3; ++i)
1020  {
1021  //__COUT__ << fields[i].first << __E__;
1022 
1023  if(fields[i].second.isLinkNode())
1024  {
1025  recursiveTreeToFhicl(
1026  fields[i].second, out, tabStr, commentStr, depth - 1);
1027  continue;
1028  }
1029  // else a normal field
1030 
1031  OUT << fields[i].second.getFieldName() << ": \t";
1032  if(fields[i].second.isValueNumberDataType())
1033  OUT << fields[i].second.getValueAsString() << __E__;
1034  else
1035  OUT << "\"" << fields[i].second.getValueAsString() << "\"" << __E__;
1036 
1037  } // end fe fields
1038 
1039  } // close UID content
1040  POPTAB; // close UID decoration
1041  OUT << "} //end " << node.getValueAsString() << " record" << __E__;
1042 
1043  // handle link closing decoration
1044  if(node.isLinkNode())
1045  {
1046  POPTAB;
1047  OUT << "} //end " << node.getValueAsString(true /* returnLinkTableValue */)
1048  << " link record" << __E__;
1049  } // end link closing decoration
1050 
1051 } // end recursiveTreeToFhicl
1052 
1053 //==============================================================================
1057  const std::string& filePath,
1058  const std::string& dumpType,
1059  const std::string& configurationAlias,
1060  const std::string& subsystemCommonList,
1061  const std::string& subsystemCommonOverrideList,
1062  const std::string& logEntry,
1063  const std::string& activeUsers,
1064  const std::string& activeStateMachine,
1065  std::ostream& altOut /* = std::cout */)
1066 {
1067  time_t rawtime = time(0);
1068  __GEN_COUT__ << "filePath = " << filePath << __E__;
1069  __GEN_COUT__ << "dumpType = " << dumpType << __E__;
1070 
1071  std::ofstream fs;
1072  if(filePath != "")
1073  fs.open(filePath, std::fstream::out | std::fstream::trunc);
1074 
1075  std::ostream* out;
1076 
1077  // if file was valid use it, else default to cout
1078  if(fs.is_open())
1079  out = &fs;
1080  else
1081  {
1082  if(filePath != "")
1083  {
1084  __SS__ << "Invalid file path to dump active configuration. File " << filePath
1085  << " could not be opened!" << __E__;
1086  __GEN_COUT_ERR__ << ss.str();
1087  __SS_THROW__;
1088  }
1089  out = &(altOut);
1090  }
1091 
1092  if(dumpType == "JSON All")
1093  {
1094  (*out) << "{\n";
1095  (*out) << "\t\"ARTDAQ_DATABASE_URI\": \"" << __ENV__("ARTDAQ_DATABASE_URI")
1096  << "\"," << __E__;
1097  if(fs.is_open())
1098  {
1099  (*out) << "\t\"HOSTNAME\": \"" << __ENV__("HOSTNAME") << "\"," << __E__;
1100  (*out) << "\t\"HOSTNAME filepath\": \"" << filePath << "\"," << __E__;
1101  (*out) << "\t\"Active State Machine\": \"" << activeStateMachine << "\","
1102  << __E__;
1103  }
1104  (*out) << "\t\"active_users\": \t[";
1105  if(activeUsers.size())
1106  {
1107  std::istringstream iss(activeUsers);
1108  std::string user;
1109  bool first = true;
1110  while(std::getline(iss, user, ','))
1111  {
1112  if(!first)
1113  (*out) << ",";
1114  (*out) << "\n\t\t\"" << user << "\"";
1115  first = false;
1116  }
1117  }
1118  (*out) << "\n\t]," << __E__;
1119  (*out) << "\t\"dump_type\": \t\t\"" << dumpType << "\"," << __E__;
1120  (*out) << "\t\"dump_time\": \t\t\"" << rawtime << "\"," << __E__;
1121  (*out) << "\t\"dump_time_formatted\": \t\t\""
1122  << StringMacros::getTimestampString(rawtime) << "\"," << __E__;
1123  }
1124  else
1125  {
1126  (*out) << "#################################" << __E__;
1127  (*out) << "This is an ots system configuration dump.\n" << __E__;
1128  (*out) << "Source database is $ARTDAQ_DATABASE_URI: "
1129  << __ENV__("ARTDAQ_DATABASE_URI") << __E__;
1130  if(fs.is_open())
1131  (*out) << "Original location of dump: " << __ENV__("HOSTNAME")
1132  << ":" << filePath << __E__;
1133  (*out) << "\nActive ots users: \t"
1134  << (activeUsers.size() ? activeUsers : "no active users") << __E__;
1135  (*out) << "Type of dump: \t\t" << dumpType << __E__;
1136  (*out) << "Time of dump: \t\t" << rawtime;
1137  (*out) << " \t" << StringMacros::getTimestampString(rawtime) << __E__;
1138  }
1139 
1140  //determine configurationAlias tranlation
1141  std::pair<std::string, ots::TableGroupKey> configurationTableGroup =
1142  getTableGroupFromAlias(configurationAlias);
1143 
1144  if(dumpType != "JSON All")
1145  {
1146  (*out) << "Configuration Alias: \t\t\t" << configurationAlias << "\n";
1147  (*out) << "Configuration Alias translation: \t" << configurationTableGroup.first
1148  << "(" << configurationTableGroup.second << ")\n\n";
1149 
1150  if(logEntry.size())
1151  (*out) << "User Log Entry (" << logEntry.size() << " chars):\n"
1152  << logEntry << __E__;
1153  }
1154 
1155  // define local "lambda" functions
1156  // active groups
1157  // active tables
1158  // active group members
1159  // active table contents
1160 
1161  //============================
1162  auto localDumpActiveGroups = [](const ConfigurationManager* cfgMgr,
1163  std::ostream* out,
1164  std::string subsystemCommonList,
1165  std::string subsystemCommonOverrideList,
1166  bool jsonify = false,
1167  std::string configurationAlias = "") {
1168  std::map<std::string, std::pair<std::string, TableGroupKey>> activeGroups =
1169  cfgMgr->getActiveTableGroups();
1170 
1171  if(jsonify)
1172  {
1173  if(!subsystemCommonList.empty())
1174  (*out) << "\n\t\"subsystem_common_table_list\": \"" << subsystemCommonList
1175  << "\"," << __E__;
1176  if(!subsystemCommonOverrideList.empty())
1177  (*out) << "\n\t\"subsystem_common_override_table_list\": \""
1178  << subsystemCommonOverrideList << "\",\n"
1179  << __E__;
1180  (*out) << "\n\t\"groups\": {\n";
1181  }
1182  else
1183  {
1184  (*out) << "Subsystem Common Table List: " << subsystemCommonList << __E__;
1185  (*out) << "Subsystem Common Override Table List: "
1186  << subsystemCommonOverrideList << __E__;
1187  (*out) << "\n\n************************" << __E__;
1188  (*out) << "Active Groups: " << __E__;
1189  }
1190 
1191  std::map<std::string, std::pair<std::string, TableGroupKey>>::iterator it;
1192 
1193  for(it = activeGroups.begin(); it != activeGroups.end(); ++it)
1194  {
1195  if(jsonify)
1196  {
1197  (*out) << "\t\t\"" << it->first << "_group_name\": \"" << it->second.first
1198  << "\",\n";
1199  (*out) << "\t\t\"" << it->first << "_group_key\": \"" << it->second.second
1200  << "\"";
1201  if(it->first == "Configuration")
1202  {
1203  (*out) << ",\n";
1204  (*out) << "\t\t\""
1205  << "Configuration_alias\": \"" << configurationAlias << "\"";
1206  }
1207  (*out) << (std::next(it) == activeGroups.end() ? "" : ",") << "\n";
1208  }
1209  else
1210  {
1211  (*out) << "\t" << it->first << " := " << it->second.first << " ("
1212  << it->second.second << ")" << __E__;
1213  }
1214  }
1215 
1216  if(jsonify)
1217  (*out) << "\t}";
1218  }; //end localDumpActiveGroups()
1219 
1220  //============================
1221  auto localDumpActiveTables = [](const ConfigurationManager* cfgMgr,
1222  std::ostream* out,
1223  bool jsonify = false) {
1224  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
1225 
1226  if(jsonify)
1227  {
1228  (*out) << "\t\"tables\": { " << __E__;
1229  }
1230  else
1231  {
1232  (*out) << "\n\n************************" << __E__;
1233  (*out) << "Active Tables:" << __E__;
1234  (*out) << "Active Tables count = " << activeTables.size() << __E__;
1235  }
1236 
1237  unsigned int i = 0;
1238  std::map<std::string, TableVersion>::iterator it;
1239  for(it = activeTables.begin(); it != activeTables.end(); ++it)
1240  {
1241  if(jsonify)
1242  {
1243  (*out) << "\t\t\""
1244  << "active_table_name"
1245  << "\": \"" << it->first << "\",\n";
1246  (*out) << "\t\t\""
1247  << "active_table_version"
1248  << "\": \"" << it->second << "\"";
1249  (*out) << (std::next(it) == activeTables.end() ? "" : ",") << "\n";
1250  }
1251  else
1252  {
1253  (*out) << "\t" << ++i << ". " << it->first << "-v" << it->second << __E__;
1254  }
1255  }
1256 
1257  if(jsonify)
1258  (*out) << "\t}";
1259  }; //end localDumpActiveTables()
1260 
1261  //============================
1262  auto localDumpActiveGroupMembers = [](ConfigurationManager* cfgMgr,
1263  std::ostream* out,
1264  bool jsonify = false) {
1265  std::map<std::string, std::pair<std::string, TableGroupKey>> activeGroups =
1266  cfgMgr->getActiveTableGroups();
1267 
1268  if(jsonify)
1269  {
1270  (*out) << "\t\"group_members\": { " << __E__;
1271  }
1272  else
1273  {
1274  (*out) << "\n\n************************" << __E__;
1275  (*out) << "Active Group Members:" << __E__;
1276  }
1277 
1278  int tableCount = 0;
1279  std::map<std::string, std::pair<std::string, TableGroupKey>>::iterator it;
1280  for(it = activeGroups.begin(); it != activeGroups.end(); ++it)
1281  {
1282  if(!jsonify)
1283  {
1284  (*out) << "\t" << it->first << " := " << it->second.first << " ("
1285  << it->second.second << ")" << __E__;
1286  }
1287 
1288  if(it->second.first == "")
1289  {
1290  if(!jsonify)
1291  {
1292  (*out) << "\t"
1293  << "Empty group name. Assuming no active group." << __E__;
1294  }
1295  continue;
1296  }
1297 
1298  if(jsonify)
1299  {
1300  (*out) << "\t\t\"" << it->first << "\" : {" << __E__;
1301  (*out) << "\t\t\t\"Name\": \t\"" << it->second.first << "\""
1302  << (std::next(it) == activeGroups.end() ? "" : ",") << __E__;
1303  }
1304 
1305  std::map<std::string /*name*/, TableVersion /*version*/> memberMap;
1306  std::map<std::string /*name*/, std::string /*alias*/> groupAliases;
1307  std::string groupComment;
1308  std::string groupAuthor;
1309  std::string groupCreateTime;
1310  time_t groupCreateTime_t;
1311 
1312  cfgMgr->loadTableGroup(it->second.first,
1313  it->second.second,
1314  false /*doActivate*/,
1315  &memberMap /*memberMap*/,
1316  0 /*progressBar*/,
1317  0 /*accumulateErrors*/,
1318  &groupComment,
1319  &groupAuthor,
1320  &groupCreateTime,
1321  true /*doNotLoadMembers*/,
1322  0 /*groupTypeString*/,
1323  &groupAliases);
1324 
1325  if(jsonify)
1326  {
1327  (*out) << "\t\t\t\"key\": \t\"" << it->second.second << "\"," << __E__;
1328  (*out) << "\t\t\t\"comment\": \t\"" << groupComment << "\"," << __E__;
1329  (*out) << "\t\t\t\"author\": \t\"" << groupAuthor << "\"," << __E__;
1330 
1331  sscanf(groupCreateTime.c_str(), "%ld", &groupCreateTime_t);
1332  std::string timeCreated = ctime(&groupCreateTime_t);
1333  (*out) << "\t\t\t\"create_time\": \t\""
1334  << timeCreated.erase(timeCreated.find('\n', 0), 1) << "\","
1335  << __E__;
1336  (*out) << "\t\t\t\"group_aliases\": \t\""
1337  << StringMacros::mapToString(groupAliases) << "\"," << __E__;
1338 
1339  (*out) << "\t\t\t\"table_count\": \t\"" << memberMap.size() << "\","
1340  << __E__;
1341  tableCount += memberMap.size();
1342 
1343  (*out) << "\t\t\t\"tables\": {" << __E__;
1344 
1345  std::map<std::string /*name*/, TableVersion /*version*/>::iterator
1346  iterMap;
1347  for(iterMap = memberMap.begin(); iterMap != memberMap.end(); ++iterMap)
1348  {
1349  (*out) << "\t\t\t\t\"" << iterMap->first << "\": \""
1350  << iterMap->second << "\""
1351  << (std::next(iterMap) == memberMap.end() ? "" : ",") << __E__;
1352  }
1353  (*out) << "\t\t\t}" << __E__;
1354  (*out) << "\t\t}," << __E__;
1355  }
1356  else
1357  {
1358  (*out) << "\t\tGroup Comment: \t" << groupComment << __E__;
1359  (*out) << "\t\tGroup Author: \t" << groupAuthor << __E__;
1360 
1361  sscanf(groupCreateTime.c_str(), "%ld", &groupCreateTime_t);
1362  (*out) << "\t\tGroup Create Time: \t" << ctime(&groupCreateTime_t)
1363  << __E__;
1364  (*out) << "\t\tGroup Aliases: \t"
1365  << StringMacros::mapToString(groupAliases) << __E__;
1366 
1367  (*out) << "\t\tMember table count = " << memberMap.size() << __E__;
1368  tableCount += memberMap.size();
1369 
1370  unsigned int i = 0;
1371  for(auto& member : memberMap)
1372  {
1373  (*out) << "\t\t\t" << ++i << ". " << member.first << "-v"
1374  << member.second << __E__;
1375  }
1376  }
1377  }
1378 
1379  if(jsonify)
1380  {
1381  (*out) << "\t\"total_table_count\": \"" << tableCount << "\"" << __E__;
1382  (*out) << "\t}";
1383  }
1384  else
1385  {
1386  (*out) << "\nActive Group Members total table count = " << tableCount
1387  << __E__;
1388  }
1389  }; //end localDumpActiveGroupMembers()
1390 
1391  //============================
1392  auto localDumpActiveTableContents = [](const ConfigurationManager* cfgMgr,
1393  std::ostream* out,
1394  bool jsonify = false) {
1395  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
1396 
1397  if(jsonify)
1398  {
1399  (*out) << "\t\"tables\": {" << __E__;
1400  }
1401  else
1402  {
1403  (*out) << "\n\n************************" << __E__;
1404  (*out) << "Active Table Contents (table count = " << activeTables.size()
1405  << "):" << __E__;
1406  }
1407 
1408  unsigned int i = 0;
1409  std::map<std::string, TableVersion>::iterator it;
1410  for(it = activeTables.begin(); it != activeTables.end(); ++it)
1411  {
1412  if(jsonify)
1413  {
1414  __COUTT__ << "localDumpActiveTableContents table: " << it->first << __E__;
1415  auto table = cfgMgr->nameToTableMap_.find(it->first)->second->getViewP();
1416  (*out) << "\t\t\"" << it->first << "-v" << it->second << "\": ";
1417  table->printJSON(*out);
1418  (*out) << (std::next(it) == activeTables.end() ? "" : ",") << __E__;
1419  }
1420  else
1421  {
1422  (*out) << "\n\n=========================================================="
1423  "===="
1424  "================"
1425  << __E__;
1426  (*out) << "=============================================================="
1427  "===="
1428  "============"
1429  << __E__;
1430  (*out) << "\t" << ++i << ". " << it->first << "-v" << it->second << __E__;
1431 
1432  cfgMgr->nameToTableMap_.find(it->first)->second->print(*out);
1433  }
1434  }
1435 
1436  if(jsonify)
1437  {
1438  (*out) << "\t}" << __E__;
1439  }
1440  }; //end localDumpActiveTableContents()
1441 
1442  //============================
1443  auto localDumpActiveTableStructureStatus = [](ConfigurationManager* cfgMgr,
1444  std::ostream* out) {
1445  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
1446 
1447  __COUT__ << "Active Table size: " << activeTables.size() << __E__;
1448  (*out) << "\t\"custom\": {" << __E__;
1449 
1450  std::string activeTableStructure = "";
1451  std::map<std::string, TableVersion>::iterator it;
1452  size_t tableStructureFoundCount = 0;
1453  for(it = activeTables.begin(); it != activeTables.end(); ++it)
1454  {
1455  try
1456  {
1457  __COUTT__ << "Trying to retrieve " << it->first << "-v" << it->second
1458  << " Structure" << __E__;
1459  activeTableStructure =
1460  cfgMgr->nameToTableMap_.find(it->first)->second->getStructureAsJSON(
1461  cfgMgr);
1462  if(activeTableStructure != "")
1463  {
1464  __COUTT__ << "Found Structure for Active Table: " << it->first << "-v"
1465  << it->second << __E__;
1466 
1467  (*out) << (tableStructureFoundCount++ ? "," : "") << __E__;
1468 
1469  (*out) << "\t\"" << it->first << "\": " << __E__;
1470  (*out) << activeTableStructure << __E__;
1471  }
1472  }
1473  catch(const std::exception& e)
1474  {
1475  __COUTT__ << "Error caught in localDumpActiveTableStructureStatus(): "
1476  << e.what();
1477  __COUTT__ << "Structure Status may not be implemented." << __E__;
1478  }
1479  } //end table structure loop
1480 
1481  __COUT__ << "Found " << tableStructureFoundCount << " Active Table Structures."
1482  << __E__;
1483 
1484  (*out) << "\t}" << __E__;
1485  }; //end localDumpActiveTableStructureStatus()
1486 
1487  //============================
1488  auto localDumpSoftwareVersions = [](std::ostream* out, bool jsonFormat = false) {
1489  __COUT__ << "localDumpSoftwareVersions()" << __E__;
1490  std::vector<std::string> entries;
1491 
1492  // collect spack output (split by newlines)
1493  std::map<std::string, std::string> spackPackages;
1494  std::map<std::string, std::string> checkedOutRepos;
1495  std::string environment;
1496 
1497  {
1498  std::string spackOut = StringMacros::exec("spack find");
1499  std::istringstream iss(spackOut);
1500  std::string line;
1501  while(std::getline(iss, line))
1502  {
1503  if(line.empty())
1504  continue;
1505 
1506  // Extract environment name
1507  if(line.find("==> In environment") != std::string::npos)
1508  {
1509  size_t start = line.find("environment ") + 12;
1510  environment = line.substr(start);
1511  }
1512  else if(line[0] != '[' && line[0] != '-' &&
1513  line.find("root specs") == std::string::npos)
1514  {
1515  // Parse spack packages
1516  size_t atPos = line.find('@');
1517  if(atPos != std::string::npos)
1518  {
1519  std::string pkgName = line.substr(0, atPos);
1520  // Remove leading [+] or [^] markers
1521  if(pkgName.find('[') != std::string::npos)
1522  pkgName = pkgName.substr(pkgName.find(']') + 2);
1523  std::string version = line.substr(atPos + 1);
1524  spackPackages[pkgName] = version;
1525  }
1526  else if(line.find('[') == std::string::npos && !line.empty() &&
1527  line[0] != 'c')
1528  {
1529  // Plain package name without version
1530  std::string pkgName = line;
1531  if(pkgName.find('[') != std::string::npos)
1532  pkgName = pkgName.substr(pkgName.find(']') + 2);
1533  spackPackages[pkgName] = "";
1534  }
1535  }
1536  }
1537  }
1538 
1539  // Collect checked out repositories
1540  {
1541  DIR* pDIR;
1542  struct dirent* entry;
1543  bool isDir;
1544  std::string name;
1545  int type;
1546  std::string src = __ENV__("OTS_SOURCE");
1547  if(!(pDIR = opendir((src).c_str())))
1548  {
1549  __SS__ << "Path '" << src << "' could not be opened!" << __E__;
1550  __SS_THROW__;
1551  }
1552  while((entry = readdir(pDIR)))
1553  {
1554  name = std::string(entry->d_name);
1555  type = int(entry->d_type);
1556 
1557  __COUTS__(2) << type << " " << name << "\n" << std::endl;
1558  if(name[0] != '.' &&
1559  (type == 0 || // 0 == UNKNOWN (which can happen - seen in SL7 VM)
1560  type == 4 || // directory type
1561  type == 8 || // file type
1562  type ==
1563  10 // 10 == link (could be directory or file, treat as unknown)
1564  ))
1565  {
1566  isDir = false;
1567 
1568  if(type == 0 || type == 10)
1569  {
1570  // unknown type .. determine if directory
1571  DIR* pTmpDIR = opendir((src + "/" + name).c_str());
1572  if(pTmpDIR)
1573  {
1574  isDir = true;
1575  closedir(pTmpDIR);
1576  }
1577  else //assume file
1578  __COUTS__(2) << "Unable to open path as directory: "
1579  << (src + "/" + name) << __E__;
1580  }
1581 
1582  if(type == 4)
1583  isDir = true; // flag directory types
1584 
1585  // handle directories
1586 
1587  if(isDir)
1588  {
1589  __COUTS__(2) << "Directory: " << type << " " << name << __E__;
1590  std::string describe = StringMacros::exec(
1591  ("cd " + src + "/" + name + "; git describe --tags").c_str());
1592  if(describe.size())
1593  {
1594  // strip trailing newline if any
1595  if(describe.back() == '\n')
1596  describe.pop_back();
1597  checkedOutRepos[name] = describe;
1598  }
1599  }
1600  }
1601  }
1602  closedir(pDIR);
1603  }
1604 
1605  if(jsonFormat)
1606  {
1607  (*out) << "\t\"software_versions\": {" << __E__;
1608 
1609  // Output spack packages
1610  (*out) << "\t\t\"spack\": {" << __E__;
1611  bool first = true;
1612  for(const auto& pkg : spackPackages)
1613  {
1614  if(!first)
1615  (*out) << "," << __E__;
1616  (*out) << "\t\t\t\"" << StringMacros::escapeJSONStringEntities(pkg.first)
1617  << "\": \"" << StringMacros::escapeJSONStringEntities(pkg.second)
1618  << "\"";
1619  first = false;
1620  }
1621  (*out) << __E__ << "\t\t}," << __E__;
1622 
1623  // Output checked out repositories
1624  (*out) << "\t\t\"checked_out\": {" << __E__;
1625  first = true;
1626  for(const auto& repo : checkedOutRepos)
1627  {
1628  if(!first)
1629  (*out) << "," << __E__;
1630  (*out) << "\t\t\t\"" << StringMacros::escapeJSONStringEntities(repo.first)
1631  << "\": \"" << StringMacros::escapeJSONStringEntities(repo.second)
1632  << "\"";
1633  first = false;
1634  }
1635  (*out) << __E__ << "\t\t}," << __E__;
1636 
1637  // Output environment
1638  (*out) << "\t\t\"environment\": \""
1639  << StringMacros::escapeJSONStringEntities(environment) << "\""
1640  << __E__;
1641 
1642  (*out) << "\t}" << __E__;
1643  }
1644  else
1645  {
1646  (*out) << "\n\n\"Software Versions\": {" << __E__;
1647  (*out) << " \"spack\": " << spackPackages.size() << " packages," << __E__;
1648  (*out) << " \"checked_out\": " << checkedOutRepos.size() << " repositories,"
1649  << __E__;
1650  (*out) << " \"environment\": \"" << environment << "\"" << __E__;
1651  (*out) << "}" << __E__;
1652  }
1653  }; //end localDumpSoftwareVersions
1654 
1655  if(dumpType == "Group Keys")
1656  {
1657  localDumpActiveGroups(
1658  this, out, subsystemCommonList, subsystemCommonOverrideList);
1659  }
1660  else if(dumpType == "Table Versions")
1661  {
1662  localDumpActiveTables(this, out);
1663  }
1664  else if(dumpType == "Group Keys and Table Versions")
1665  {
1666  localDumpActiveGroups(
1667  this, out, subsystemCommonList, subsystemCommonOverrideList);
1668  localDumpActiveTables(this, out);
1669  }
1670  else if(dumpType == "All")
1671  {
1672  localDumpActiveGroups(
1673  this, out, subsystemCommonList, subsystemCommonOverrideList);
1674  localDumpActiveGroupMembers(this, out);
1675  localDumpActiveTables(this, out);
1676  localDumpActiveTableContents(this, out);
1677  localDumpSoftwareVersions(out);
1678  }
1679  else if(dumpType == "JSON All")
1680  {
1681  localDumpActiveGroups(this,
1682  out,
1683  subsystemCommonList,
1684  subsystemCommonOverrideList,
1685  true,
1686  configurationAlias);
1687  (*out) << ",\n";
1688  localDumpActiveGroupMembers(this, out, true);
1689  (*out) << ",\n";
1690  //localDumpActiveTables(this, out, true);
1691  //(*out) << ",\n" << __E__;
1692  localDumpActiveTableContents(this, out, true);
1693  (*out) << ",\n" << __E__;
1694  localDumpActiveTableStructureStatus(this, out);
1695  (*out) << ",\n" << __E__;
1696  localDumpSoftwareVersions(out, true);
1697  (*out) << "}\n";
1698  }
1699  else
1700  {
1701  __SS__
1702  << "Invalid dump type '" << dumpType
1703  << "' given during dumpActiveConfiguration(). Valid types are as follows:\n"
1704  <<
1705 
1706  // List all choices (must match accepted dumpType strings)
1707  "Group Keys"
1708  << ", "
1709  << "Table Versions"
1710  << ", "
1711  << "Group Keys and Table Versions"
1712  << ", "
1713  << "All"
1714  << ", "
1715  << "JSON All"
1716  <<
1717 
1718  "\n\nPlease change the State Machine configuration to a valid dump type."
1719  << __E__;
1720  __SS_THROW__;
1721  }
1722 
1723  if(fs.is_open())
1724  fs.close();
1725 
1726 } //end dumpActiveConfiguration()
1727 
1728 //==============================================================================
1735  const std::map<std::string /*name*/, TableVersion /*version*/>& memberMap,
1736  std::string* accumulatedWarnings /* =0 */)
1737 {
1738  __GEN_COUTTV__(runTimeSeconds());
1739 
1740  TableBase* tmpTableBasePtr;
1741 
1742  //detect if using cache, and decide if multi-threading
1743  bool usingCache = false;
1744  if(memberMap.size() > 10 && nameToTableMap_.size() &&
1745  nameToTableMap_.find(memberMap.begin()->first) != nameToTableMap_.end() &&
1746  nameToTableMap_.at(memberMap.begin()->first)->isStored(memberMap.begin()->second))
1747  {
1748  usingCache = true;
1749  }
1750  if(usingCache)
1751  __GEN_COUTT__ << "Using cache!" << __E__;
1752 
1753  //Note: mongodb crashing from too many connections was resolved by increasing ulimit at mongodb launch
1754  // i.e. ulimit -n 64000 && ./start_mongod.sh
1755  const int numOfThreads = StringMacros::getConcurrencyCount() / 2 < memberMap.size()
1756  ? (StringMacros::getConcurrencyCount() / 2)
1757  : memberMap.size();
1758  if(memberMap.size() <= 2 /* i.e. is Context group */ || usingCache ||
1759  numOfThreads < 2) // no multi-threading
1760  {
1761  // for each member
1762  // get()
1763  for(auto& memberPair : memberMap)
1764  {
1765  // if(accumulatedWarnings)
1766  // __GEN_COUT__ << "\tFilling member table " << memberPair.first << ":" <<
1767  // memberPair.second << __E__;
1768 
1769  // get the proper temporary pointer
1770  // use 0 if doesn't exist yet.
1771  // Note: do not want to give nameToTableMap_[memberPair.first]
1772  // in case there is failure in get... (exceptions may be thrown)
1773  // Note: Default constructor is called by Map, i.e.
1774  // nameToTableMap_[memberPair.first] = 0; //create pointer and set to 0
1775  tmpTableBasePtr = nullptr;
1776  if(nameToTableMap_.find(memberPair.first) != nameToTableMap_.end())
1777  tmpTableBasePtr = nameToTableMap_.at(memberPair.first);
1778 
1779  std::string getError = "";
1780  try
1781  {
1782  theInterface_->get(tmpTableBasePtr, // tablePtr
1783  memberPair.first, // tableName
1784  0, // groupKey
1785  0, // groupName
1786  false, // dontFill=false to fill
1787  memberPair.second, // version
1788  false // resetTable
1789  );
1790  }
1791  catch(const std::runtime_error& e)
1792  {
1793  __SS__ << "Failed to load member table '" << memberPair.first << "-v"
1794  << memberPair.second << "' - here is the error: \n\n"
1795  << e.what() << __E__;
1796 
1797  ss << "\nIf the table '" << memberPair.first
1798  << "' should not exist, then please remove it from the group. If it "
1799  "should exist, then it "
1800  << "seems to have a problem; use the Table Editor to fix the table "
1801  "definition, or "
1802  "edit the table content to match the table definition."
1803  << __E__;
1804 
1805  // if accumulating warnings and table view was created, then continue
1806  if(accumulatedWarnings)
1807  getError = ss.str();
1808  else
1809  __SS_ONLY_THROW__;
1810  }
1811  catch(...)
1812  {
1813  __SS__ << "Failed to load member table '" << memberPair.first << " -v"
1814  << memberPair.second << "' due to unknown error!" << __E__;
1815  try
1816  {
1817  throw;
1818  } //one more try to printout extra info
1819  catch(const std::exception& e)
1820  {
1821  ss << "Exception message: " << e.what();
1822  }
1823  catch(...)
1824  {
1825  }
1826 
1827  ss << "\nIf the table '" << memberPair.first
1828  << "' should not exist, then please remove it from the group. If it "
1829  "should exist, then it "
1830  << "seems to have a problem; use the Table Editor to fix the table "
1831  "definition, or "
1832  "edit the table content to match the table definition."
1833  << __E__;
1834 
1835  // if accumulating warnings and table view was created, then continue
1836  if(accumulatedWarnings)
1837  getError = ss.str();
1838  else
1839  __SS_THROW__;
1840  }
1841 
1842  //__GEN_COUT__ << "Checking ptr.. " << (tmpTableBasePtr?"GOOD":"BAD") << __E__;
1843  if(!tmpTableBasePtr)
1844  {
1845  __SS__ << "Null pointer returned for table '" << memberPair.first << " -v"
1846  << memberPair.second << ".' Was the table info deleted?" << __E__;
1847  __GEN_COUT_ERR__ << ss.str();
1848 
1849  nameToTableMap_.erase(memberPair.first);
1850  if(accumulatedWarnings)
1851  {
1852  *accumulatedWarnings += ss.str();
1853  continue;
1854  }
1855  else
1856  __SS_ONLY_THROW__;
1857  }
1858 
1859  nameToTableMap_[memberPair.first] = tmpTableBasePtr;
1860  if(nameToTableMap_[memberPair.first]->getViewP())
1861  {
1862  //__GEN_COUT__ << "Activated version: " <<
1863  // nameToTableMap_[memberPair.first]->getViewVersion() << __E__;
1864 
1865  if(accumulatedWarnings && getError != "")
1866  {
1867  __SS__ << "Error caught during '" << memberPair.first << " -v"
1868  << memberPair.second << "' table retrieval: \n"
1869  << getError << __E__;
1870  __GEN_COUT_ERR__ << ss.str();
1871  *accumulatedWarnings += ss.str();
1872  }
1873  }
1874  else
1875  {
1876  __SS__ << nameToTableMap_[memberPair.first]->getTableName() << " -v"
1877  << memberPair.second << ": View version not activated properly!";
1878  __SS_THROW__;
1879  }
1880  } // end member map loop
1881  }
1882  else //multi-threading
1883  {
1884  __GEN_COUTT__ << " getConcurrencyCount " << StringMacros::getConcurrencyCount()
1885  << " ==> " << numOfThreads
1886  << " threads for loading member map of size " << memberMap.size()
1887  << __E__;
1888 
1889  int threadsLaunched = 0;
1890  int foundThreadIndex = 0;
1891  std::string threadErrors;
1892  std::mutex threadMutex; // to protect accumulatedWarnings
1893  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
1894  for(int i = 0; i < numOfThreads; ++i)
1895  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
1896  std::vector<TableBase*> tmpTableBasePtrs;
1897  for(int i = 0; i < numOfThreads; ++i)
1898  tmpTableBasePtrs.push_back(nullptr);
1899 
1900  for(auto& memberPair : memberMap)
1901  {
1902  if(threadsLaunched >= numOfThreads)
1903  {
1904  //find availableThreadIndex
1905  foundThreadIndex = -1;
1906  while(foundThreadIndex == -1)
1907  {
1908  for(int i = 0; i < numOfThreads; ++i)
1909  if(*(threadDone[i]))
1910  {
1911  foundThreadIndex = i;
1912  break;
1913  }
1914  if(foundThreadIndex == -1)
1915  {
1916  __GEN_COUTT__ << "Waiting for available thread..." << __E__;
1917  usleep(10000);
1918  }
1919  } //end thread search loop
1920  threadsLaunched = numOfThreads - 1;
1921  }
1922  __GEN_COUTT__ << "Starting filling thread... " << foundThreadIndex << " for "
1923  << memberPair.first << " -v" << memberPair.second << __E__;
1924  *(threadDone[foundThreadIndex]) = false;
1925 
1926  // get the proper temporary pointer
1927  // use 0 if doesn't exist yet.
1928  // Note: do not want to give nameToTableMap_[memberPair.first]
1929  // in case there is failure in get... (exceptions may be thrown)
1930  // Note: Default constructor is called by Map, i.e.
1931  // nameToTableMap_[memberPair.first] = 0; //create pointer and set to 0
1932  tmpTableBasePtrs[foundThreadIndex] = nullptr;
1933  if(nameToTableMap_.find(memberPair.first) != nameToTableMap_.end())
1934  tmpTableBasePtrs[foundThreadIndex] = nameToTableMap_.at(memberPair.first);
1935 
1936  std::thread(
1937  [](ConfigurationInterface* theInterface,
1938  std::map<std::string, ots::TableBase*>* theNameToTableMap,
1939  ots::TableBase* theTable,
1940  std::string theTableName,
1941  ots::TableVersion version,
1942  std::string* theThreadErrors,
1943  std::mutex* theThreadMutex,
1944  std::shared_ptr<std::atomic<bool>> theThreadDone) {
1945  ConfigurationManager::fillTableThread(theInterface,
1946  theNameToTableMap,
1947  theTable,
1948  theTableName,
1949  version,
1950  theThreadErrors,
1951  theThreadMutex,
1952  theThreadDone);
1953  },
1954  theInterface_,
1955  &nameToTableMap_,
1956  tmpTableBasePtrs[foundThreadIndex],
1957  memberPair.first,
1958  memberPair.second,
1959  &threadErrors,
1960  &threadMutex,
1961  threadDone[foundThreadIndex])
1962  .detach();
1963 
1964  ++threadsLaunched;
1965  ++foundThreadIndex;
1966  } //end table init thread loop
1967 
1968  //check for all threads done
1969  do
1970  {
1971  foundThreadIndex = -1;
1972  for(int i = 0; i < numOfThreads; ++i)
1973  if(!*(threadDone[i]))
1974  {
1975  foundThreadIndex = i;
1976  break;
1977  }
1978  if(foundThreadIndex != -1)
1979  {
1980  __GEN_COUT_TYPE__(TLVL_DEBUG + 2)
1981  << __COUT_HDR__ << "Waiting for thread to finish... "
1982  << foundThreadIndex << __E__;
1983  usleep(10000);
1984  }
1985  } while(foundThreadIndex != -1); //end thread done search loop
1986  __GEN_COUTT__ << "All threads done." << __E__;
1987 
1988  if(threadErrors != "")
1989  {
1990  __SS__ << "Error identified in threads during loading of member map: \n"
1991  << threadErrors << __E__;
1992  __GEN_COUTT__ << "\n" << ss.str() << __E__;
1993  if(accumulatedWarnings)
1994  *accumulatedWarnings += ss.str();
1995  else
1996  __SS_THROW__;
1997  }
1998  } //end multi-thread handling
1999 
2000  __GEN_COUTT__ << "loadMemberMap end runTimeSeconds()=" << runTimeSeconds() << __E__;
2001 } // end loadMemberMap()
2002 
2003 //==============================================================================
2026  const std::string& groupName,
2027  const TableGroupKey& groupKey,
2028  bool doActivate /*=false*/,
2029  std::map<std::string /*table name*/, TableVersion>*
2030  groupMembers /*=0 , note: db time intensive! */,
2031  ProgressBar* progressBar /*=0*/,
2032  std::string* accumulatedWarnings /*=0*/,
2033  std::string* groupComment /*=0 , note: in metadata */,
2034  std::string* groupAuthor /*=0 , note: in metadata */,
2035  std::string* groupCreateTime /*=0 , note: in metadata */,
2036  bool doNotLoadMembers /*=false*/,
2037  std::string* groupTypeString /*=0 , note: db time intensive! */,
2038  std::map<std::string /*name*/, std::string /*alias*/>*
2039  groupAliases /*=0 , note: in metadata */,
2040  ConfigurationManager::LoadGroupType
2041  groupTypeToLoad /*=ConfigurationManager::LoadGroupType::ALL_TYPES*/,
2042  bool ignoreVersionTracking /*=false*/,
2043  std::map<std::string /* tableName */, TableVersion> mergInTables /*={}*/,
2044  std::map<std::string /* tableName */, TableVersion> overrideTables /*={}*/)
2045 {
2046  // clear to defaults
2047  if(groupComment)
2048  *groupComment = ConfigurationManager::UNKNOWN_INFO;
2049  if(groupAuthor)
2050  *groupAuthor = ConfigurationManager::UNKNOWN_INFO;
2051  if(groupCreateTime)
2052  *groupCreateTime = ConfigurationManager::UNKNOWN_TIME;
2053  if(groupTypeString)
2054  *groupTypeString = ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
2055  else
2056  __GEN_COUTT__ << "No group type requested." << __E__;
2057 
2058  // if(groupName == "defaultConfig")
2059  // { //debug active versions
2060  // std::map<std::string, TableVersion> allActivePairs = getActiveVersions();
2061  // for(auto& activePair: allActivePairs)
2062  // {
2063  // __GEN_COUT__ << "Active table = " <<
2064  // activePair.first << "-v" <<
2065  // getTableByName(activePair.first)->getView().getVersion() <<
2066  // __E__;
2067  // }
2068  // }
2069 
2070  // load all members of configuration group
2071  // if doActivate
2072  // determine the type configuration
2073  // deactivate all of that type (invalidate active view)
2074  //
2075  // for each member
2076  // get()
2077  // if doActivate, configBase->init()
2078  //
2079  // if doActivate
2080  // set theConfigurationTableGroup_, theContextTableGroup_, or
2081  // theBackboneTableGroup_ on success
2082 
2083  __GEN_COUTT__ << "Loading Table Group: " << groupName << "(" << groupKey << ")"
2084  << " accumulatedWarnings=" << (accumulatedWarnings ? 1 : 0) << __E__;
2085 
2086  //failing member map load should be an exception!
2087 
2088  std::map<std::string /*name*/, TableVersion /*version*/> memberMap =
2089  theInterface_->getTableGroupMembers(
2090  TableGroupKey::getFullGroupString(groupName, groupKey),
2091  true /*include meta data table*/);
2092 
2093  try
2094  {
2095  if(progressBar)
2096  progressBar->step();
2097 
2098  // remove meta data table and extract info
2099  auto metaTablePair = memberMap.find(TableBase::GROUP_METADATA_TABLE_NAME);
2100  if(metaTablePair != memberMap.end())
2101  {
2102  //only lock metadata table if metadata is needed
2103  if(groupAliases || groupComment || groupAuthor || groupCreateTime)
2104  {
2105  std::lock_guard<std::mutex> lock(metaDataTableMutex_);
2106 
2107  // clear table
2108  while(groupMetadataTable_.getView().getNumberOfRows())
2109  groupMetadataTable_.getViewP()->deleteRow(0);
2110 
2111  // retrieve metadata from database
2112  try
2113  {
2114  theInterface_->fill(&groupMetadataTable_, metaTablePair->second);
2115  }
2116  catch(const std::runtime_error& e)
2117  {
2118  __GEN_COUT_WARN__
2119  << "Failed to load " << groupMetadataTable_.getTableName() << "-v"
2120  << metaTablePair->second << ". Metadata error: " << e.what()
2121  << __E__;
2122  }
2123  catch(...)
2124  {
2125  __GEN_COUT_WARN__
2126  << "Failed to load " << groupMetadataTable_.getTableName() << "-v"
2127  << metaTablePair->second << ". Ignoring unknown metadata error. "
2128  << __E__;
2129  }
2130 
2131  // check that there is only 1 row
2132  if(groupMetadataTable_.getView().getNumberOfRows() != 1)
2133  {
2134  groupMetadataTable_.print();
2135  __GEN_COUT_ERR__ << "Ignoring that groupMetadataTable_ has wrong "
2136  "number of rows for '"
2137  << groupName << "(" << groupKey
2138  << ")!' Must "
2139  "be 1. Going with anonymous defaults."
2140  << __E__;
2141 
2142  // fix metadata table
2143  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
2144  groupMetadataTable_.getViewP()->deleteRow(0);
2145  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
2146  groupMetadataTable_.getViewP()->addRow();
2147  }
2148  else
2149  {
2150  // extract metadata fields
2151 
2152  if(groupAliases)
2154  groupMetadataTable_.getView().getValueAsString(
2155  0, ConfigurationManager::METADATA_COL_ALIASES),
2156  *groupAliases);
2157  if(groupComment)
2158  *groupComment = groupMetadataTable_.getView().getValueAsString(
2159  0, ConfigurationManager::METADATA_COL_COMMENT);
2160  if(groupAuthor)
2161  *groupAuthor = groupMetadataTable_.getView().getValueAsString(
2162  0, ConfigurationManager::METADATA_COL_AUTHOR);
2163  if(groupCreateTime)
2164  *groupCreateTime = groupMetadataTable_.getView().getValueAsString(
2165  0, ConfigurationManager::METADATA_COL_TIMESTAMP);
2166  }
2167  }
2168 
2169  memberMap.erase(metaTablePair); // remove from member map that is returned
2170 
2171  } // end metadata handling
2172  else
2173  {
2174  __GEN_COUTT__ << "Ignoring that groupMetadataTable_ is missing for group '"
2175  << groupName << "(" << groupKey
2176  << "). Going with anonymous defaults." << __E__;
2177  }
2178 
2179  //NEVER modify members based on aliases
2180  // Regarding Member Table Aliases: alias names are tracked in the metadata table,
2181  // however! The group member versions are decided at group save time
2182  // (loadTableGroup should always return the same groupName -> memberMap translation).
2183  // The group member versions do not undergo alias translation at load time (i.e. loadTableGroup).
2184  // The alias map can be retrieved using the groupAliases parameter.
2185  if(0)
2186  {
2187  std::map<std::string, std::string>& aliasMap = *groupAliases;
2188  std::map<std::string /*table*/, std::map<std::string /*alias*/, TableVersion>>
2189  versionAliases;
2190  if(aliasMap.size()) // load version aliases
2191  {
2192  __GEN_COUTV__(StringMacros::mapToString(aliasMap));
2193  versionAliases = ConfigurationManager::getVersionAliases();
2194  __GEN_COUTV__(StringMacros::mapToString(versionAliases));
2195  }
2196 
2197  // convert alias to version
2198  for(auto& aliasPair : aliasMap)
2199  {
2200  // check for alias table in member names
2201  if(memberMap.find(aliasPair.first) != memberMap.end())
2202  {
2203  __GEN_COUT__ << "Group member '" << aliasPair.first
2204  << "' was found in group member map!" << __E__;
2205  __GEN_COUT__ << "Looking for alias '" << aliasPair.second
2206  << "' in active version aliases..." << __E__;
2207 
2208  if(versionAliases.find(aliasPair.first) == versionAliases.end() ||
2209  versionAliases[aliasPair.first].find(aliasPair.second) ==
2210  versionAliases[aliasPair.first].end())
2211  {
2212  __SS__ << "Group '" << groupName << "(" << groupKey
2213  << ")' requires table version alias '" << aliasPair.first
2214  << ":" << aliasPair.second
2215  << ",' which was not found in the active Backbone!"
2216  << __E__;
2217  __SS_ONLY_THROW__;
2218  }
2219 
2220  memberMap[aliasPair.first] =
2221  versionAliases[aliasPair.first][aliasPair.second];
2222  __GEN_COUT__ << "Version alias translated to " << aliasPair.first
2223  << __E__;
2224  }
2225  }
2226  } // end modify members based on aliases
2227 
2228  if(groupMembers)
2229  *groupMembers = memberMap; // copy map for return
2230 
2231  if(progressBar)
2232  progressBar->step();
2233 
2234  ConfigurationManager::GroupType groupType =
2235  ConfigurationManager::GroupType::CONFIGURATION_TYPE;
2236  try
2237  {
2238  if(groupTypeString) // do before exit case
2239  {
2240  groupType = getTypeOfGroup(memberMap);
2241  *groupTypeString = convertGroupTypeToName(groupType);
2242  }
2243  else
2244  __GEN_COUTT__ << "No group type requested." << __E__;
2245 
2246  if(doNotLoadMembers)
2247  return; //this is useful if just getting group metadata
2248 
2249  // if not already done, determine the type configuration group
2250  if(!groupTypeString)
2251  groupType = getTypeOfGroup(memberMap);
2252 
2253  if(groupTypeToLoad ==
2254  ConfigurationManager::LoadGroupType::ONLY_BACKBONE_OR_CONTEXT_TYPES &&
2255  groupType != ConfigurationManager::GroupType::CONTEXT_TYPE &&
2256  groupType != ConfigurationManager::GroupType::BACKBONE_TYPE)
2257  {
2258  __GEN_COUT__ << "Not loading group because it is not of type Context or "
2259  "Backbone (it is type '"
2260  << convertGroupTypeToName(groupType) << "')." << __E__;
2261  return;
2262  }
2263  else if(groupTypeToLoad ==
2264  ConfigurationManager::LoadGroupType::ONLY_BACKBONE_TYPE &&
2265  groupType != ConfigurationManager::GroupType::BACKBONE_TYPE)
2266  {
2267  __GEN_COUT__ << "Not loading group because it is not of type "
2268  "Backbone (it is type '"
2269  << convertGroupTypeToName(groupType) << "')." << __E__;
2270  return;
2271  }
2272 
2273  __GEN_COUTTV__(StringMacros::mapToString(getActiveVersions()));
2274  if(doActivate)
2275  __GEN_COUT__
2276  << "------------------------------------- init start \t [for all "
2277  "plug-ins in "
2278  << convertGroupTypeToName(groupType) << " group '" << groupName << "("
2279  << groupKey << ")"
2280  << "']" << __E__;
2281 
2282  if(doActivate)
2283  {
2284  std::string groupToDeactivate =
2285  groupType == ConfigurationManager::GroupType::CONTEXT_TYPE
2286  ? theContextTableGroup_
2287  : (groupType == ConfigurationManager::GroupType::BACKBONE_TYPE
2288  ? theBackboneTableGroup_
2289  : (groupType ==
2290  ConfigurationManager::GroupType::ITERATE_TYPE
2291  ? theIterateTableGroup_
2292  : theConfigurationTableGroup_));
2293 
2294  // deactivate all of that type (invalidate active view)
2295  if(groupToDeactivate != "") // deactivate only if pre-existing group
2296  {
2297  __GEN_COUTT__ << "groupToDeactivate '" << groupToDeactivate
2298  << "' of type " << convertGroupTypeToName(groupType)
2299  << __E__;
2300  destroyTableGroup(groupToDeactivate, true);
2301  }
2302  else
2303  {
2304  //Getting here, is kind of strange:
2305  // - this group may have only been partially loaded before?
2306  __GEN_COUTT__ << "no group to deactivate of type "
2307  << convertGroupTypeToName(groupType) << __E__;
2308  }
2309  __GEN_COUTTV__(StringMacros::mapToString(getActiveVersions()));
2310  }
2311 
2312  if(progressBar)
2313  progressBar->step();
2314 
2315  loadMemberMap(memberMap, accumulatedWarnings);
2316 
2317  if(progressBar)
2318  progressBar->step();
2319 
2320  __GEN_COUTT__ << "loadMemberMap() completed." << __E__;
2321 
2322  if(accumulatedWarnings)
2323  {
2324  __GEN_COUTT__ << "Checking chosen group for tree errors... here are the "
2325  "current warnings: "
2326  << *accumulatedWarnings << __E__;
2327 
2328  getChildren(&memberMap, accumulatedWarnings);
2329  if(*accumulatedWarnings != "")
2330  {
2331  __GEN_COUT_WARN__
2332  << "Errors detected while loading Table Group: " << groupName
2333  << "(" << groupKey << "). Ignoring the following errors: "
2334  << "\n"
2335  << *accumulatedWarnings << __E__;
2336  }
2337  __GEN_COUTT__ << "After checking children warnings: "
2338  << *accumulatedWarnings << __E__;
2339  }
2340 
2341  if(progressBar)
2342  progressBar->step();
2343 
2344  __GEN_COUTT__ << "Tree view check complete." << __E__;
2345 
2346  // for each member
2347  // if doActivate, configBase->init()
2348  if(doActivate)
2349  {
2350  __GEN_COUTTV__(StringMacros::mapToString(getActiveVersions()));
2351 
2352  if(overrideTables.size())
2353  {
2354  __GEN_COUT__ << "Overriding tables: "
2355  << StringMacros::mapToString(overrideTables) << __E__;
2356 
2357  std::map<std::pair<std::string /*original table*/,
2358  std::string /*original uidB*/>,
2359  std::string /*converted uidB*/>
2360  uidConversionMap;
2361  std::map<std::pair<std::string /*original table*/,
2362  std::pair<std::string /*group linkid*/,
2363  std::string /*original gidB*/>>,
2364  std::string /*converted gidB*/>
2365  groupidConversionMap;
2366 
2367  for(const auto& mergeInPair : overrideTables)
2368  {
2369  if(memberMap.find(mergeInPair.first) == memberMap.end())
2370  {
2371  __GEN_COUT__ << "Skipping override of table '"
2372  << mergeInPair.first << "-v"
2373  << mergeInPair.second
2374  << "' which is not in group " << groupName << "("
2375  << groupKey << ")." << __E__;
2376  continue;
2377  }
2378  __GEN_COUT__ << "Overriding group member table '"
2379  << mergeInPair.first << "' v"
2380  << memberMap.at(mergeInPair.first)
2381  << " with version v" << mergeInPair.second << __E__;
2382 
2383  std::stringstream mergeReport;
2384  TableVersion newVersion =
2385  nameToTableMap_.at(mergeInPair.first)
2386  ->mergeViews(
2388  mergeInPair.first,
2389  memberMap.at(mergeInPair.first))
2390  ->getView() /* sourceViewA */,
2391  getVersionedTableByName(mergeInPair.first,
2392  mergeInPair.second)
2393  ->getView() /* sourceViewB*/,
2394  TableVersion() /* destinationVersion*/,
2395  "override-table",
2396  TableBase::MergeApproach::REPLACE, //mergeApproach
2397  uidConversionMap, //should not used for Replace mode
2398  groupidConversionMap, //should not used for Replace mode
2399  false /* fillRecordConversionMaps */,
2400  true /* applyRecordConversionMaps */,
2401  false /* generateUniqueDataColumns */,
2402  &mergeReport); // dont make destination version the first time
2403 
2404  __GEN_COUTV__(newVersion);
2405  nameToTableMap_.at(mergeInPair.first)->setActiveView(newVersion);
2406  nameToTableMap_.at(mergeInPair.first)
2407  ->getViewP()
2408  ->setComment(nameToTableMap_.at(mergeInPair.first)
2409  ->getView()
2410  .getComment() +
2411  "\n" + mergeReport.str());
2412  __GEN_COUT__ << "Overriding table '" << mergeInPair.first
2413  << "' resulting version v" << newVersion << __E__;
2414  __GEN_COUTV__(mergeReport.str());
2415  } //end merge-in table loop
2416 
2417  __GEN_COUTV__(StringMacros::mapToString(getActiveVersions()));
2418  }
2419 
2420  if(mergInTables.size())
2421  {
2422  __GEN_COUT__ << "Merging-in tables: "
2423  << StringMacros::mapToString(mergInTables) << __E__;
2424 
2425  std::map<std::pair<std::string /*original table*/,
2426  std::string /*original uidB*/>,
2427  std::string /*converted uidB*/>
2428  uidConversionMap;
2429  std::map<std::pair<std::string /*original table*/,
2430  std::pair<std::string /*group linkid*/,
2431  std::string /*original gidB*/>>,
2432  std::string /*converted gidB*/>
2433  groupidConversionMap;
2434 
2435  for(const auto& mergeInPair : mergInTables)
2436  {
2437  if(memberMap.find(mergeInPair.first) == memberMap.end())
2438  {
2439  __GEN_COUT__ << "Skipping merging-in of table '"
2440  << mergeInPair.first << "-v"
2441  << mergeInPair.second
2442  << "' which is not in group " << groupName << "("
2443  << groupKey << ")." << __E__;
2444  continue;
2445  }
2446 
2447  __GEN_COUT__ << "Merging-in group member table '"
2448  << mergeInPair.first << "' v"
2449  << memberMap.at(mergeInPair.first)
2450  << " with version v" << mergeInPair.second << __E__;
2451 
2452  std::stringstream mergeReport;
2453  TableVersion newVersion =
2454  nameToTableMap_.at(mergeInPair.first)
2455  ->mergeViews(
2457  mergeInPair.first,
2458  memberMap.at(mergeInPair.first))
2459  ->getView() /* sourceViewA */,
2460  getVersionedTableByName(mergeInPair.first,
2461  mergeInPair.second)
2462  ->getView() /* sourceViewB*/,
2463  TableVersion() /* destinationVersion*/,
2464  "merge-in-table",
2465  TableBase::MergeApproach::SKIP, //mergeApproach
2466  uidConversionMap, //should not used for Skip mode
2467  groupidConversionMap, //should not used for Skip mode
2468  false /* fillRecordConversionMaps */,
2469  true /* applyRecordConversionMaps */,
2470  false /* generateUniqueDataColumns */,
2471  &mergeReport); // dont make destination version the first time
2472 
2473  __GEN_COUTV__(newVersion);
2474  nameToTableMap_.at(mergeInPair.first)->setActiveView(newVersion);
2475  nameToTableMap_.at(mergeInPair.first)
2476  ->getViewP()
2477  ->setComment(nameToTableMap_.at(mergeInPair.first)
2478  ->getView()
2479  .getComment() +
2480  "\n" + mergeReport.str());
2481  __GEN_COUT__ << "Merging-in table '" << mergeInPair.first
2482  << "' resulting version v" << newVersion << __E__;
2483  __GEN_COUTV__(mergeReport.str());
2484  } //end merge-in table loop
2485 
2486  __GEN_COUTV__(StringMacros::mapToString(getActiveVersions()));
2487  } //end merge-in table handling
2488 
2489  if(progressBar)
2490  progressBar->step();
2491 
2492  const int numOfThreads = StringMacros::getConcurrencyCount() / 2;
2493  __GEN_COUTT__ << " getConcurrencyCount "
2494  << StringMacros::getConcurrencyCount() << " ==> "
2495  << numOfThreads
2496  << " threads for initializing tables for Table Group '"
2497  << groupName << "(" << groupKey << ")'." << __E__;
2498  if(groupType != ConfigurationManager::GroupType::CONFIGURATION_TYPE ||
2499  numOfThreads < 2) // no multi-threading
2500  {
2501  for(auto& memberPair : memberMap)
2502  {
2503  // do NOT allow activating Scratch versions if tracking is ON!
2504  if(!ignoreVersionTracking &&
2505  ConfigurationInterface::isVersionTrackingEnabled() &&
2506  memberPair.second.isScratchVersion())
2507  {
2508  __SS__
2509  << "Error while activating member Table '"
2510  << nameToTableMap_[memberPair.first]->getTableName()
2511  << "-v" << memberPair.second << " for Table Group '"
2512  << groupName << "(" << groupKey
2513  << ")'. When version tracking is enabled, Scratch views"
2514  << " are not allowed! Please only use unique, persistent "
2515  "versions when version tracking is enabled."
2516  << __E__;
2517  __SS_ONLY_THROW__;
2518  }
2519 
2520  // attempt to init using the configuration's specific init
2521  // this could be risky user code, try and catch
2522  try
2523  {
2524  nameToTableMap_.at(memberPair.first)->init(this);
2525  }
2526  catch(std::runtime_error& e)
2527  {
2528  __SS__ << "Error detected calling " << memberPair.first
2529  << ".init()!\n\n " << e.what() << __E__;
2530 
2531  if(accumulatedWarnings)
2532  {
2533  *accumulatedWarnings += ss.str();
2534  }
2535  else
2536  {
2537  ss << StringMacros::stackTrace();
2538  __SS_ONLY_THROW__;
2539  }
2540  }
2541  catch(...)
2542  {
2543  __SS__ << "Unknown Error detected calling "
2544  << memberPair.first << ".init()!\n\n " << __E__;
2545  try
2546  {
2547  throw;
2548  } //one more try to printout extra info
2549  catch(const std::exception& e)
2550  {
2551  ss << "Exception message: " << e.what();
2552  }
2553  catch(...)
2554  {
2555  }
2556  //__SS_THROW__;
2557 
2558  if(accumulatedWarnings)
2559  {
2560  *accumulatedWarnings += ss.str();
2561  }
2562  else // ignore error
2563  __GEN_COUT_WARN__ << ss.str();
2564  }
2565  }
2566  }
2567  else //multi-threading
2568  {
2569  int threadsLaunched = 0;
2570  int foundThreadIndex = 0;
2571  std::string threadErrors;
2572  std::mutex threadMutex; // to protect accumulatedWarnings
2573  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
2574  for(int i = 0; i < numOfThreads; ++i)
2575  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
2576 
2577  if(!ignoreVersionTracking &&
2578  ConfigurationInterface::isVersionTrackingEnabled())
2579  for(auto& memberPair : memberMap)
2580  {
2581  // do NOT allow activating Scratch versions if tracking is ON!
2582  if(memberPair.second.isScratchVersion())
2583  {
2584  __SS__
2585  << "Error while activating member Table '"
2586  << nameToTableMap_[memberPair.first]->getTableName()
2587  << "-v" << memberPair.second << " for Table Group '"
2588  << groupName << "(" << groupKey
2589  << ")'. When version tracking is enabled, Scratch "
2590  "views"
2591  << " are not allowed! Please only use unique, "
2592  "persistent "
2593  "versions when version tracking is enabled."
2594  << __E__;
2595  __SS_ONLY_THROW__;
2596  }
2597  }
2598 
2599  for(auto& memberPair : memberMap)
2600  {
2601  if(threadsLaunched >= numOfThreads)
2602  {
2603  //find availableThreadIndex
2604  foundThreadIndex = -1;
2605  while(foundThreadIndex == -1)
2606  {
2607  for(int i = 0; i < numOfThreads; ++i)
2608  if(*(threadDone[i]))
2609  {
2610  foundThreadIndex = i;
2611  break;
2612  }
2613  if(foundThreadIndex == -1)
2614  {
2615  __GEN_COUTT__ << "Waiting for available thread..."
2616  << __E__;
2617  usleep(10000);
2618  }
2619  } //end thread search loop
2620  threadsLaunched = numOfThreads - 1;
2621  }
2622  __GEN_COUTT__ << "Starting init table thread... "
2623  << foundThreadIndex << " for " << memberPair.first
2624  << __E__;
2625  *(threadDone[foundThreadIndex]) = false;
2626 
2627  std::thread(
2628  [](ConfigurationManager* cfgMgr,
2629  ots::TableBase* theTable,
2630  std::string* theThreadErrors,
2631  std::mutex* theThreadMutex,
2632  std::shared_ptr<std::atomic<bool>> theThreadDone) {
2633  ConfigurationManager::initTableThread(cfgMgr,
2634  theTable,
2635  theThreadErrors,
2636  theThreadMutex,
2637  theThreadDone);
2638  },
2639  this,
2640  nameToTableMap_.at(memberPair.first),
2641  &threadErrors,
2642  &threadMutex,
2643  threadDone[foundThreadIndex])
2644  .detach();
2645 
2646  ++threadsLaunched;
2647  ++foundThreadIndex;
2648  } //end table init thread loop
2649 
2650  //check for all threads done
2651  do
2652  {
2653  foundThreadIndex = -1;
2654  for(int i = 0; i < numOfThreads; ++i)
2655  if(!*(threadDone[i]))
2656  {
2657  foundThreadIndex = i;
2658  break;
2659  }
2660  if(foundThreadIndex != -1)
2661  {
2662  __GEN_COUTT__ << "Waiting for thread to finish... "
2663  << foundThreadIndex << __E__;
2664  usleep(10000);
2665  }
2666  } while(foundThreadIndex != -1); //end thread done search loop
2667  __GEN_COUTT__ << "All threads done." << __E__;
2668 
2669  if(threadErrors != "")
2670  {
2671  __SS__ << "Error identified in threads during init of table "
2672  "group: \n"
2673  << threadErrors << __E__;
2674  __GEN_COUTT__ << "\n" << ss.str() << __E__;
2675  if(accumulatedWarnings)
2676  *accumulatedWarnings += ss.str();
2677  else
2678  __SS_THROW__;
2679  }
2680  } //end multi-thread handling
2681 
2682  __GEN_COUTTV__(StringMacros::mapToString(getActiveVersions()));
2683  } //end activate/init of member tables
2684 
2685  if(progressBar)
2686  progressBar->step();
2687 
2688  // if doActivate
2689  // set theConfigurationTableGroup_, theContextTableGroup_, or
2690  // theBackboneTableGroup_ on
2691  // success
2692 
2693  if(doActivate)
2694  {
2695  if(groupType == ConfigurationManager::GroupType::CONTEXT_TYPE) //
2696  {
2697  // __GEN_COUT_INFO__ << "Type=Context, Group loaded: " <<
2698  // groupName
2699  //<<
2700  // "(" << groupKey << ")" << __E__;
2701  theContextTableGroup_ = groupName;
2702  theContextTableGroupKey_ =
2703  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
2704  }
2705  else if(groupType == ConfigurationManager::GroupType::BACKBONE_TYPE)
2706  {
2707  // __GEN_COUT_INFO__ << "Type=Backbone, Group loaded: " <<
2708  // groupName <<
2709  // "(" << groupKey << ")" << __E__;
2710  theBackboneTableGroup_ = groupName;
2711  theBackboneTableGroupKey_ =
2712  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
2713  }
2714  else if(groupType == ConfigurationManager::GroupType::ITERATE_TYPE)
2715  {
2716  // __GEN_COUT_INFO__ << "Type=Iterate, Group loaded: " <<
2717  // groupName
2718  //<<
2719  // "(" << groupKey << ")" << __E__;
2720  theIterateTableGroup_ = groupName;
2721  theIterateTableGroupKey_ =
2722  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
2723  }
2724  else // is theConfigurationTableGroup_
2725  {
2726  // __GEN_COUT_INFO__ << "Type=Configuration, Group loaded: " <<
2727  // groupName <<
2728  // "(" << groupKey << ")" << __E__;
2729  theConfigurationTableGroup_ = groupName;
2730  theConfigurationTableGroupKey_ =
2731  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
2732  }
2733  }
2734 
2735  if(progressBar)
2736  progressBar->step();
2737 
2738  if(doActivate)
2739  __GEN_COUT__
2740  << "------------------------------------- init complete \t [for all "
2741  "plug-ins in "
2742  << convertGroupTypeToName(groupType) << " group '" << groupName << "("
2743  << groupKey << ")"
2744  << "']" << __E__;
2745  } // end failed group load try
2746  catch(...)
2747  {
2748  // save group name and key of failed load attempt
2749  lastFailedGroupLoad_[convertGroupTypeToName(groupType)] =
2750  std::pair<std::string, TableGroupKey>(groupName, TableGroupKey(groupKey));
2751 
2752  try
2753  {
2754  throw;
2755  }
2756  catch(const std::runtime_error& e)
2757  {
2758  __SS__ << "Error occurred while loading table group '" << groupName << "("
2759  << groupKey << ")': \n"
2760  << e.what() << __E__;
2761 
2762  if(accumulatedWarnings)
2763  *accumulatedWarnings += ss.str();
2764  else
2765  __SS_ONLY_THROW__;
2766  }
2767  catch(...)
2768  {
2769  __SS__ << "An unknown error occurred while loading table group '"
2770  << groupName << "(" << groupKey << ")." << __E__;
2771  try
2772  {
2773  throw;
2774  } //one more try to printout extra info
2775  catch(const std::exception& e)
2776  {
2777  ss << "Exception message: " << e.what();
2778  }
2779  catch(...)
2780  {
2781  }
2782  if(accumulatedWarnings)
2783  *accumulatedWarnings += ss.str();
2784  else
2785  __SS_ONLY_THROW__;
2786  }
2787  }
2788 
2789  __GEN_COUTT__ << "loadTableGroup() complete for Table Group '" << groupName << "("
2790  << groupKey << ")'." << __E__;
2791  lastGroupLoad_[convertGroupTypeToName(groupType)] =
2792  std::make_pair(std::make_pair(groupName, TableGroupKey(groupKey)), memberMap);
2793  return;
2794  }
2795  catch(...)
2796  {
2797  __GEN_COUTT__ << "loadTableGroup() failed." << __E__;
2798 
2799  // save group name and key of failed load attempt
2800  lastFailedGroupLoad_[ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN] =
2801  std::pair<std::string, TableGroupKey>(groupName, TableGroupKey(groupKey));
2802 
2803  try
2804  {
2805  throw;
2806  }
2807  catch(const std::runtime_error& e)
2808  {
2809  __SS__ << "Error occurred while loading table group '" << groupName << "("
2810  << groupKey << ")': \n"
2811  << e.what() << __E__;
2812 
2813  if(accumulatedWarnings)
2814  *accumulatedWarnings += ss.str();
2815  else
2816  __SS_ONLY_THROW__;
2817  }
2818  catch(...)
2819  {
2820  __SS__ << "An unknown error occurred while loading table group '" << groupName
2821  << "(" << groupKey << ")." << __E__;
2822  try
2823  {
2824  throw;
2825  } //one more try to printout extra info
2826  catch(const std::exception& e)
2827  {
2828  ss << "Exception message: " << e.what();
2829  }
2830  catch(...)
2831  {
2832  }
2833  __GEN_COUT__ << StringMacros::stackTrace();
2834 
2835  if(accumulatedWarnings)
2836  *accumulatedWarnings += ss.str();
2837  else
2838  __SS_ONLY_THROW__;
2839  }
2840  }
2841 } // end loadTableGroup()
2842 
2843 //==============================================================================
2847  const ConfigurationManager& cacheConfigMgr,
2848  const std::map<std::string, TableVersion>& memberMap,
2849  const std::string& groupName /* = "" */,
2850  const TableGroupKey& groupKey /* = TableGroupKey::Invalid */,
2851  bool doActivate /* = false */,
2852  bool ignoreVersionTracking /* = false */)
2853 {
2854  //Note: mostly copied from onfigurationManager::loadTableGroup()
2855 
2856  // determine the type table group type for activation and to save last loaded types
2857  ConfigurationManager::GroupType groupType = getTypeOfGroup(memberMap);
2858  try
2859  {
2860  if(doActivate)
2861  __GEN_COUT__ << "------------------------------------- cacheCopy init start "
2862  " \t [for all "
2863  "plug-ins in member map"
2864  << "']" << __E__;
2865 
2866  if(doActivate)
2867  {
2868  std::string groupToDeactivate =
2869  groupType == ConfigurationManager::GroupType::CONTEXT_TYPE
2870  ? theContextTableGroup_
2871  : (groupType == ConfigurationManager::GroupType::BACKBONE_TYPE
2872  ? theBackboneTableGroup_
2873  : (groupType == ConfigurationManager::GroupType::ITERATE_TYPE
2874  ? theIterateTableGroup_
2875  : theConfigurationTableGroup_));
2876 
2877  // deactivate all of that type (invalidate active view)
2878  if(groupToDeactivate != "") // deactivate only if pre-existing group
2879  {
2880  //__GEN_COUT__ << "groupToDeactivate '" << groupToDeactivate << "'" <<
2881  // __E__;
2882  destroyTableGroup(groupToDeactivate, true);
2883  }
2884  // else
2885  // {
2886  // //Getting here, is kind of strange:
2887  // // - this group may have only been partially loaded before?
2888  // }
2889  }
2890 
2891  //Now load member map, copied from ConfigurationManager::loadMemberMap
2892  // loadMemberMap(memberMap, accumulatedWarnings);
2893  // for each member
2894  // get()
2895  for(auto& memberPair : memberMap)
2896  {
2897  __GEN_COUTT__ << "Copying " << memberPair.first << "-v" << memberPair.second
2898  << __E__;
2899 
2900  //if table does not exist, create it
2901  if(nameToTableMap_.find(memberPair.first) == nameToTableMap_.end())
2902  {
2903  TableBase* table = 0;
2904  theInterface_->get(table, // configurationPtr
2905  memberPair.first, // tableName
2906  0, // groupKey
2907  0, // groupName
2908  true // dontFill=false to fill
2909  );
2910 
2911  nameToTableMap_[memberPair.first] = table;
2912  }
2913  nameToTableMap_.at(memberPair.first)
2914  ->copyView(cacheConfigMgr.getTableByName(memberPair.first)
2915  ->getView(memberPair.second),
2916  memberPair.second,
2917  cacheConfigMgr.getTableByName(memberPair.first)
2918  ->getView(memberPair.second)
2919  .getAuthor(),
2920  true /* looseColumnMatching */);
2921 
2922  //Note: copyView does not make the new view the active view,
2923  // to make the new view the active view do this:
2924  // nameToTableMap_.at(memberPair.first)->setActiveView(memberPair.second);
2925  } //end member map copy loop
2926  __GEN_COUTT__ << "Done with member copy loop." << __E__;
2927 
2928  // for each member
2929  // if doActivate, configBase->init()
2930  if(doActivate)
2931  {
2932  std::string accumulatedWarnings;
2933  const int numOfThreads = StringMacros::getConcurrencyCount() / 2;
2934  __GEN_COUT__ << " getConcurrencyCount " << StringMacros::getConcurrencyCount()
2935  << " ==> " << numOfThreads << " threads for initializing tables."
2936  << __E__;
2937  if(groupType != ConfigurationManager::GroupType::CONFIGURATION_TYPE ||
2938  numOfThreads < 2) // no multi-threading
2939  {
2940  for(auto& memberPair : memberMap)
2941  {
2942  // do NOT allow activating Scratch versions if tracking is ON!
2943  if(!ignoreVersionTracking &&
2944  ConfigurationInterface::isVersionTrackingEnabled() &&
2945  memberPair.second.isScratchVersion())
2946  {
2947  __SS__ << "Error while activating member Table '"
2948  << nameToTableMap_[memberPair.first]->getTableName()
2949  << "-v" << memberPair.second
2950  << " for member map. When version tracking is enabled, "
2951  "Scratch views"
2952  << " are not allowed! Please only use unique, persistent "
2953  "versions when version tracking is enabled."
2954  << __E__;
2955  __SS_ONLY_THROW__;
2956  }
2957 
2958  // attempt to init using the configuration's specific init
2959  // this could be risky user code, try and catch
2960  try
2961  {
2962  nameToTableMap_.at(memberPair.first)->init(this);
2963  }
2964  catch(std::runtime_error& e)
2965  {
2966  __SS__ << "Error detected calling " << memberPair.first
2967  << ".init()!\n\n " << e.what() << __E__;
2968  accumulatedWarnings += ss.str();
2969  }
2970  catch(...)
2971  {
2972  __SS__ << "Unknown Error detected calling " << memberPair.first
2973  << ".init()!\n\n " << __E__;
2974  try
2975  {
2976  throw;
2977  } //one more try to printout extra info
2978  catch(const std::exception& e)
2979  {
2980  ss << "Exception message: " << e.what();
2981  }
2982  catch(...)
2983  {
2984  }
2985  accumulatedWarnings += ss.str();
2986  }
2987  }
2988  }
2989  else //multi-threading
2990  {
2991  int threadsLaunched = 0;
2992  int foundThreadIndex = 0;
2993  std::mutex threadMutex; // to protect accumulatedWarnings
2994  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
2995  for(int i = 0; i < numOfThreads; ++i)
2996  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
2997 
2998  if(!ignoreVersionTracking &&
2999  ConfigurationInterface::isVersionTrackingEnabled())
3000  for(auto& memberPair : memberMap)
3001  {
3002  // do NOT allow activating Scratch versions if tracking is ON!
3003  if(memberPair.second.isScratchVersion())
3004  {
3005  __SS__
3006  << "Error while activating member Table '"
3007  << nameToTableMap_[memberPair.first]->getTableName()
3008  << "-v" << memberPair.second
3009  << " for member map. When version tracking is enabled, "
3010  "Scratch views"
3011  << " are not allowed! Please only use unique, persistent "
3012  "versions when version tracking is enabled."
3013  << __E__;
3014  __SS_ONLY_THROW__;
3015  }
3016  }
3017 
3018  for(auto& memberPair : memberMap)
3019  {
3020  if(threadsLaunched >= numOfThreads)
3021  {
3022  //find availableThreadIndex
3023  foundThreadIndex = -1;
3024  while(foundThreadIndex == -1)
3025  {
3026  for(int i = 0; i < numOfThreads; ++i)
3027  if(*(threadDone[i]))
3028  {
3029  foundThreadIndex = i;
3030  break;
3031  }
3032  if(foundThreadIndex == -1)
3033  {
3034  __GEN_COUTT__ << "Waiting for available thread..."
3035  << __E__;
3036  usleep(10000);
3037  }
3038  } //end thread search loop
3039  threadsLaunched = numOfThreads - 1;
3040  }
3041  __GEN_COUTT__ << "Starting init table thread... " << foundThreadIndex
3042  << " for " << memberPair.first << __E__;
3043  *(threadDone[foundThreadIndex]) = false;
3044 
3045  std::thread(
3046  [](ConfigurationManager* cfgMgr,
3047  ots::TableBase* theTable,
3048  std::string* theAccumulatedWarnings,
3049  std::mutex* theThreadMutex,
3050  std::shared_ptr<std::atomic<bool>> theThreadDone) {
3051  ConfigurationManager::initTableThread(cfgMgr,
3052  theTable,
3053  theAccumulatedWarnings,
3054  theThreadMutex,
3055  theThreadDone);
3056  },
3057  this,
3058  nameToTableMap_.at(memberPair.first),
3059  &accumulatedWarnings,
3060  &threadMutex,
3061  threadDone[foundThreadIndex])
3062  .detach();
3063 
3064  ++threadsLaunched;
3065  ++foundThreadIndex;
3066  } //end table init thread loop
3067 
3068  //check for all threads done
3069  do
3070  {
3071  foundThreadIndex = -1;
3072  for(int i = 0; i < numOfThreads; ++i)
3073  if(!*(threadDone[i]))
3074  {
3075  foundThreadIndex = i;
3076  break;
3077  }
3078  if(foundThreadIndex != -1)
3079  {
3080  __GEN_COUTT__ << "Waiting for thread to finish... "
3081  << foundThreadIndex << __E__;
3082  usleep(10000);
3083  }
3084  } while(foundThreadIndex != -1); //end thread done search loop
3085 
3086  } //end multi-thread handling
3087 
3088  if(accumulatedWarnings != "")
3089  {
3090  __GEN_COUT__ << "Activating the member map after copying cache had the "
3091  "following warnings: "
3092  << accumulatedWarnings << __E__;
3093  }
3094  } //end activate/init of member tables
3095 
3096  // if doActivate
3097  // set theConfigurationTableGroup_, theContextTableGroup_, or
3098  // theBackboneTableGroup_ on
3099  // success
3100 
3101  if(doActivate)
3102  {
3103  if(groupType == ConfigurationManager::GroupType::CONTEXT_TYPE) //
3104  {
3105  // __GEN_COUT_INFO__ << "Type=Context, Group loaded: " <<
3106  // groupName
3107  //<<
3108  // "(" << groupKey << ")" << __E__;
3109  theContextTableGroup_ = groupName;
3110  theContextTableGroupKey_ =
3111  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
3112  }
3113  else if(groupType == ConfigurationManager::GroupType::BACKBONE_TYPE)
3114  {
3115  // __GEN_COUT_INFO__ << "Type=Backbone, Group loaded: " <<
3116  // groupName <<
3117  // "(" << groupKey << ")" << __E__;
3118  theBackboneTableGroup_ = groupName;
3119  theBackboneTableGroupKey_ =
3120  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
3121  }
3122  else if(groupType == ConfigurationManager::GroupType::ITERATE_TYPE)
3123  {
3124  // __GEN_COUT_INFO__ << "Type=Iterate, Group loaded: " <<
3125  // groupName
3126  //<<
3127  // "(" << groupKey << ")" << __E__;
3128  theIterateTableGroup_ = groupName;
3129  theIterateTableGroupKey_ =
3130  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
3131  }
3132  else // is theConfigurationTableGroup_
3133  {
3134  // __GEN_COUT_INFO__ << "Type=Configuration, Group loaded: " <<
3135  // groupName <<
3136  // "(" << groupKey << ")" << __E__;
3137  theConfigurationTableGroup_ = groupName;
3138  theConfigurationTableGroupKey_ =
3139  std::shared_ptr<TableGroupKey>(new TableGroupKey(groupKey));
3140  }
3141  }
3142 
3143  if(doActivate)
3144  __GEN_COUT__ << "------------------------------------- cacheCopy init "
3145  "complete \t [for all "
3146  "plug-ins in member map"
3147  << "']" << __E__;
3148 
3149  __GEN_COUTT__ << "Completed cache copy." << __E__;
3150  if(groupName != "" && !TableGroupKey(groupKey).isInvalid())
3151  lastGroupLoad_[convertGroupTypeToName(groupType)] =
3152  make_pair(make_pair(groupName, TableGroupKey(groupKey)), memberMap);
3153  } // end failed group load try
3154  catch(...)
3155  {
3156  __GEN_COUT__ << "Unknown failure in cache copy." << __E__;
3157  // save group name and key of failed load attempt
3158  lastFailedGroupLoad_[convertGroupTypeToName(groupType)] =
3159  std::pair<std::string, TableGroupKey>(groupName, TableGroupKey(groupKey));
3160  throw;
3161  } //end unknown failure handling
3162 } // end copyTableGroupFromCache()
3163 
3164 //==============================================================================
3165 std::pair<std::string /* groupName */, TableGroupKey>
3166 ConfigurationManager::getGroupOfLoadedTable(const std::string& tableName) const
3167 {
3168  for(const auto& loadedGroup : lastGroupLoad_) //search the loaded group member map
3169  if(loadedGroup.second.second.find(tableName) != loadedGroup.second.second.end())
3170  return loadedGroup.second.first; //found! so return group name/key
3171  return std::make_pair("", TableGroupKey(TableGroupKey::INVALID));
3172 } // end getGroupOfLoadedTable()
3173 
3174 //==============================================================================
3176 void ConfigurationManager::initTableThread(ConfigurationManager* cfgMgr,
3177  ots::TableBase* table,
3178  std::string* threadErrors,
3179  std::mutex* threadMutex,
3180  std::shared_ptr<std::atomic<bool>> threadDone)
3181 try
3182 {
3183  __COUTT__ << "Thread init of " << table->getTableName() << "-v"
3184  << table->getViewVersion() << " threadErrors=" << (threadErrors ? 1 : 0)
3185  << __E__;
3186 
3187  // attempt to init using the configuration's specific init
3188  // this could be risky user code, try and catch
3189  try
3190  {
3191  __COUTTV__(StringMacros::mapToString(cfgMgr->getActiveVersions()));
3192  table->init(cfgMgr);
3193  }
3194  catch(std::runtime_error& e)
3195  {
3196  __SS__ << "Error detected calling " << table->getTableName() << ".init()!\n\n "
3197  << e.what() << __E__;
3198 
3199  if(threadErrors)
3200  {
3201  std::lock_guard<std::mutex> lock(*threadMutex);
3202  *threadErrors += ss.str();
3203  }
3204  else
3205  {
3206  ss << StringMacros::stackTrace();
3207  __SS_ONLY_THROW__;
3208  }
3209  }
3210  catch(...)
3211  {
3212  __SS__ << "Unknown Error detected calling " << table->getTableName()
3213  << ".init()!\n\n " << __E__;
3214  try
3215  {
3216  throw;
3217  } //one more try to printout extra info
3218  catch(const std::exception& e)
3219  {
3220  ss << "Exception message: " << e.what();
3221  }
3222  catch(...)
3223  {
3224  }
3225 
3226  ss << StringMacros::stackTrace();
3227 
3228  if(threadErrors)
3229  {
3230  std::lock_guard<std::mutex> lock(*threadMutex);
3231  *threadErrors += ss.str();
3232  }
3233  else
3234  __SS_ONLY_THROW__;
3235  }
3236 
3237  *(threadDone) = true;
3238 } // end initTableThread()
3239 catch(...)
3240 {
3241  __SS__ << "Error occurred initializing table '" << table->getTableName() << "-v"
3242  << table->getViewVersion() << "'..." << __E__;
3243  try
3244  {
3245  throw;
3246  }
3247  catch(const std::runtime_error& e)
3248  {
3249  ss << " Run-time Exception message: " << e.what();
3250  }
3251  catch(const std::exception& e)
3252  {
3253  ss << " Exception message: " << e.what();
3254  }
3255  __COUT_WARN__ << ss.str() << __E__;
3256 
3257  if(threadErrors)
3258  {
3259  std::lock_guard<std::mutex> lock(*threadMutex);
3260  *threadErrors += ss.str();
3261  }
3262 
3263  *(threadDone) = true;
3264 } // end initTableThread catch
3265 
3266 //==============================================================================
3268 void ConfigurationManager::fillTableThread(
3269  ConfigurationInterface* theInterface,
3270  std::map<std::string, ots::TableBase*>* nameToTableMap,
3271  ots::TableBase* table,
3272  std::string tableName,
3273  ots::TableVersion version,
3274  std::string* threadErrors,
3275  std::mutex* threadMutex,
3276  std::shared_ptr<std::atomic<bool>> threadDone)
3277 try
3278 {
3279  __COUTT__ << "Thread fill of " << tableName << "-v" << version << __E__;
3280 
3281  // std::map<std::string, ots::TableBase *> n;
3282  // std::map<std::string, ots::TableBase *>*nameToTableMap = &n;
3283  // ots::TableBase* table;
3284  // // ots::TableVersion v;
3285  // // ots::TableVersion* version = &v;
3286  // std::string a;
3287  // std::string* accumulatedWarnings = &a;
3288  // std::string tableName = "";
3289  std::string getError = "";
3290  // attempt to init using the configuration's specific init
3291  // this could be risky user code, try and catch
3292  try
3293  {
3294  theInterface->get(table, // tablePtr
3295  tableName, // tableName
3296  0, // groupKey
3297  0, // groupName
3298  false, // dontFill=false to fill
3299  version, // version
3300  false // resetTable
3301  );
3302  }
3303  catch(const std::runtime_error& e)
3304  {
3305  __SS__ << "Failed to load member table '" << tableName << "-v" << version
3306  << "' - here is the error: \n\n"
3307  << e.what() << __E__;
3308 
3309  ss << "\nIf the table '" << tableName
3310  << "' should not exist, then please remove it from the group. If it "
3311  "should exist, then it "
3312  << "seems to have a problem; use the Table Editor to fix the table "
3313  "definition, or "
3314  "edit the table content to match the table definition."
3315  << __E__;
3316 
3317  // if accumulating warnings and table view was created, then continue
3318  if(threadErrors)
3319  getError = ss.str();
3320  else
3321  __SS_ONLY_THROW__;
3322  }
3323  catch(...)
3324  {
3325  __SS__ << "Failed to load member table '" << tableName << "-v" << version
3326  << "' due to unknown error!" << __E__;
3327  try
3328  {
3329  throw;
3330  } //one more try to printout extra info
3331  catch(const std::exception& e)
3332  {
3333  ss << "Exception message: " << e.what();
3334  }
3335  catch(...)
3336  {
3337  }
3338  ss << "\nIf the table '" << tableName
3339  << "' should not exist, then please remove it from the group. If it "
3340  "should exist, then it "
3341  << "seems to have a problem; use the Table Editor to fix the table "
3342  "definition, or "
3343  "edit the table content to match the table definition."
3344  << __E__;
3345 
3346  // if accumulating warnings and table view was created, then continue
3347  if(threadErrors)
3348  getError = ss.str();
3349  else
3350  __SS_THROW__;
3351  }
3352 
3353  if(getError != "")
3354  __COUTV__(getError);
3355 
3356  __COUT_TYPE__(TLVL_TRACE + 1)
3357  << __COUT_HDR__ << "Checking ptr.. " << (table ? "GOOD" : "BAD") << __E__;
3358  if(!table)
3359  {
3360  __SS__ << "Null pointer returned for table '" << tableName
3361  << ".' Was the table info deleted?" << __E__;
3362  __COUT_ERR__ << ss.str();
3363 
3364  std::lock_guard<std::mutex> lock(*threadMutex);
3365  nameToTableMap->erase(tableName);
3366 
3367  if(threadErrors)
3368  {
3369  *threadErrors += ss.str();
3370  *(threadDone) = true;
3371  return;
3372  }
3373  else
3374  __SS_ONLY_THROW__;
3375  }
3376  else
3377  {
3378  std::lock_guard<std::mutex> lock(*threadMutex);
3379  (*nameToTableMap)[tableName] = table;
3380  }
3381 
3382  if(nameToTableMap->at(tableName)->getViewP())
3383  {
3384  __COUT_TYPE__(TLVL_TRACE + 1)
3385  << __COUT_HDR__
3386  << "Activated version: " << nameToTableMap->at(tableName)->getViewVersion()
3387  << __E__;
3388 
3389  if(threadErrors && getError != "")
3390  {
3391  __SS__ << "Error caught during '" << tableName << "' table retrieval: \n"
3392  << getError << __E__;
3393  __COUT_ERR__ << ss.str();
3394  std::lock_guard<std::mutex> lock(*threadMutex);
3395  *threadErrors += ss.str();
3396  }
3397  }
3398  else
3399  {
3400  __SS__ << tableName << ": View version not activated properly!";
3401  __SS_THROW__;
3402  }
3403 
3404  __COUTT__ << "end Thread fill of " << tableName << "-v" << version << __E__;
3405  *(threadDone) = true;
3406 } // end fillTableThread()
3407 catch(const std::runtime_error& e)
3408 {
3409  __SS__ << "Error occurred filling table '" << tableName << "-v" << version
3410  << "': " << e.what() << __E__;
3411  __COUT_ERR__ << ss.str();
3412 
3413  if(threadErrors)
3414  {
3415  std::lock_guard<std::mutex> lock(*threadMutex);
3416  *threadErrors += ss.str();
3417  }
3418 
3419  *(threadDone) = true;
3420 }
3421 catch(...)
3422 {
3423  __SS__ << "Unknwon error occurred filling table '" << tableName << "-v" << version
3424  << "'..." << __E__;
3425  try
3426  {
3427  throw;
3428  } //one more try to printout extra info
3429  catch(const std::exception& e)
3430  {
3431  ss << "Exception message: " << e.what();
3432  }
3433  catch(...)
3434  {
3435  }
3436  __COUT_ERR__ << ss.str();
3437 
3438  if(threadErrors)
3439  {
3440  std::lock_guard<std::mutex> lock(*threadMutex);
3441  *threadErrors += ss.str();
3442  }
3443 
3444  *(threadDone) = true;
3445 } // end fillTableThread catch
3446 
3447 //==============================================================================
3453  const std::string& tableName,
3454  TableVersion version,
3455  bool looseColumnMatching /* = false */,
3456  std::string* accumulatedErrors /* = 0 */,
3457  bool getRawData /* = false */,
3458  bool touchLastAccessTime /* = true */)
3459 {
3460  auto it = nameToTableMap_.find(tableName);
3461  if(it == nameToTableMap_.end())
3462  {
3463  __SS__ << "\nCan not find table named '" << tableName
3464  << "'\n\n\n\nYou need to load the table before it can be used."
3465  << "It probably is missing from the member list of the Table "
3466  "Group that was loaded?\n\n\n\n\n"
3467  << __E__;
3468  __SS_THROW__;
3469  }
3470  TableBase* table = it->second;
3471 
3472  if(version.isTemporaryVersion())
3473  {
3474  table->setActiveView(version);
3475 
3476  if(getRawData)
3477  {
3478  std::stringstream jsonSs;
3479  table->getViewP()->printJSON(jsonSs);
3480  table->getViewP()->doGetSourceRawData(true);
3481  table->getViewP()->fillFromJSON(jsonSs.str());
3482  }
3483  }
3484  else
3485  {
3486  theInterface_->get(table,
3487  tableName,
3488  0 /* groupKey */,
3489  0 /* groupName */,
3490  false /* dontFill */, // false to fill w/version
3491  version,
3492  false /* resetConfiguration*/, // false to not reset
3493  looseColumnMatching,
3494  getRawData,
3495  accumulatedErrors,
3496  touchLastAccessTime);
3497  }
3498  return table;
3499 } // end getVersionedTableByName()
3500 
3501 //==============================================================================
3507 std::map<std::string, std::pair<std::string, TableGroupKey>>
3509 {
3510  // map<type, pair <groupName , TableGroupKey> >
3511  std::map<std::string, std::pair<std::string, TableGroupKey>> retMap;
3512 
3513  retMap[ConfigurationManager::GROUP_TYPE_NAME_CONTEXT] =
3514  std::pair<std::string, TableGroupKey>(
3515  theContextTableGroup_,
3516  theContextTableGroupKey_ ? *theContextTableGroupKey_ : TableGroupKey());
3517  retMap[ConfigurationManager::GROUP_TYPE_NAME_BACKBONE] =
3518  std::pair<std::string, TableGroupKey>(
3519  theBackboneTableGroup_,
3520  theBackboneTableGroupKey_ ? *theBackboneTableGroupKey_ : TableGroupKey());
3521  retMap[ConfigurationManager::GROUP_TYPE_NAME_ITERATE] =
3522  std::pair<std::string, TableGroupKey>(
3523  theIterateTableGroup_,
3524  theIterateTableGroupKey_ ? *theIterateTableGroupKey_ : TableGroupKey());
3525  retMap[ConfigurationManager::GROUP_TYPE_NAME_CONFIGURATION] =
3526  std::pair<std::string, TableGroupKey>(theConfigurationTableGroup_,
3527  theConfigurationTableGroupKey_
3528  ? *theConfigurationTableGroupKey_
3529  : TableGroupKey());
3530  return retMap;
3531 } // end getActiveTableGroups()
3532 
3533 //==============================================================================
3534 const std::string& ConfigurationManager::getActiveGroupName(
3535  const ConfigurationManager::GroupType& type) const
3536 {
3537  if(type == ConfigurationManager::GroupType::CONFIGURATION_TYPE)
3538  return theConfigurationTableGroup_;
3539  else if(type == ConfigurationManager::GroupType::CONTEXT_TYPE)
3540  return theContextTableGroup_;
3541  else if(type == ConfigurationManager::GroupType::BACKBONE_TYPE)
3542  return theBackboneTableGroup_;
3543  else if(type == ConfigurationManager::GroupType::ITERATE_TYPE)
3544  return theIterateTableGroup_;
3545 
3546  __SS__ << "IMPOSSIBLE! Invalid type requested '" << (int)type << "'" << __E__;
3547  __SS_THROW__;
3548 } // end getActiveGroupName()
3549 
3550 //==============================================================================
3551 TableGroupKey ConfigurationManager::getActiveGroupKey(
3552  const ConfigurationManager::GroupType& type) const
3553 {
3554  if(type == ConfigurationManager::GroupType::CONFIGURATION_TYPE)
3555  return theConfigurationTableGroupKey_ ? *theConfigurationTableGroupKey_
3556  : TableGroupKey();
3557  else if(type == ConfigurationManager::GroupType::CONTEXT_TYPE)
3558  return theContextTableGroupKey_ ? *theContextTableGroupKey_ : TableGroupKey();
3559  else if(type == ConfigurationManager::GroupType::BACKBONE_TYPE)
3560  return theBackboneTableGroupKey_ ? *theBackboneTableGroupKey_ : TableGroupKey();
3561  else if(type == ConfigurationManager::GroupType::ITERATE_TYPE)
3562  return theIterateTableGroupKey_ ? *theIterateTableGroupKey_ : TableGroupKey();
3563 
3564  __SS__ << "IMPOSSIBLE! Invalid type requested '" << (int)type << "'" << __E__;
3565  __SS_THROW__;
3566 } // end getActiveGroupKey()
3567 
3568 //==============================================================================
3569 ConfigurationTree ConfigurationManager::getContextNode(
3570  const std::string& contextUID, const std::string& /*applicationUID*/) const
3571 {
3572  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
3573  contextUID);
3574 } // end getContextNode()
3575 
3576 //==============================================================================
3577 ConfigurationTree ConfigurationManager::getSupervisorNode(
3578  const std::string& contextUID, const std::string& applicationUID) const
3579 {
3580  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
3581  contextUID + "/LinkToApplicationTable/" + applicationUID);
3582 } // end getSupervisorNode()
3583 
3584 //==============================================================================
3585 ConfigurationTree ConfigurationManager::getSupervisorTableNode(
3586  const std::string& contextUID, const std::string& applicationUID) const
3587 {
3588  return getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName() + "/" +
3589  contextUID + "/LinkToApplicationTable/" + applicationUID +
3590  "/LinkToSupervisorTable");
3591 } // end getSupervisorTableNode()
3592 
3593 //==============================================================================
3596 {
3597  auto contextChildren =
3598  getNode("/" + getTableByName(XDAQ_CONTEXT_TABLE_NAME)->getTableName())
3599  .getChildren();
3600  for(const auto& contextChild : contextChildren)
3601  {
3602  auto appChildren = contextChild.second.getNode("LinkToApplicationTable")
3603  .getChildren(); //colContext_.colLinkToApplicationTable_
3604  for(const auto& appChild : appChildren)
3605  {
3606  if(appChild.second.getNode("Class").getValue() ==
3607  "ots::GatewaySupervisor") //colApplication_.colClass_ ... XDAQContextTable::GATEWAY_SUPERVISOR_CLASS)
3608  return appChild.second;
3609  }
3610  }
3611  __SS__ << "No Gateway Supervisor node found!" << __E__;
3612  __SS_THROW__;
3613 } // end getGatewaySupervisorNode()
3614 
3615 //==============================================================================
3616 ConfigurationTree ConfigurationManager::getNode(const std::string& nodeString,
3617  bool doNotThrowOnBrokenUIDLinks) const
3618 {
3619  // __GEN_COUT__ << "nodeString=" << nodeString << " len=" << nodeString.length() << __E__;
3620 
3621  // get nodeName (in case of / syntax)
3622  if(nodeString.length() < 1)
3623  {
3624  __SS__ << ("Invalid empty node name") << __E__;
3625  __GEN_SS_THROW__;
3626  }
3627 
3628  // ignore multiple starting slashes
3629  size_t startingIndex = 0;
3630  while(startingIndex < nodeString.length() && nodeString[startingIndex] == '/')
3631  ++startingIndex;
3632  size_t endingIndex = nodeString.find('/', startingIndex);
3633  if(endingIndex == std::string::npos)
3634  endingIndex = nodeString.length();
3635 
3636  std::string nodeName = nodeString.substr(startingIndex, endingIndex - startingIndex);
3637  // __GEN_COUT__ << "nodeName=" << nodeName << " len" << nodeName.length() << __E__;
3638  if(nodeName.length() < 1)
3639  {
3640  // return root node
3641  return ConfigurationTree(this, 0);
3642 
3643  // __SS__ << "Invalid node name: " << nodeName << __E__;
3644  // __GEN_COUT_ERR__ << ss.str();
3645  // __SS_THROW__;
3646  }
3647  ++endingIndex;
3648  std::string childPath =
3649  (endingIndex >= nodeString.length() ? "" : nodeString.substr(endingIndex));
3650 
3651  // __GEN_COUT__ << "childPath=" << childPath << " len=" << childPath.length() << " endingIndex=" << endingIndex << " nodeString.length()=" << nodeString.length() << __E__;
3652 
3653  ConfigurationTree configTree(this, getTableByName(nodeName));
3654 
3655  if(childPath.length() > 1)
3656  return configTree.getNode(childPath, doNotThrowOnBrokenUIDLinks);
3657  else
3658  return configTree;
3659 } // end getNode()
3660 
3661 //==============================================================================
3662 std::map<std::string, ConfigurationTree> ConfigurationManager::getNodes(
3663  const std::string& nodeString) const
3664 {
3665  return getNode(nodeString).getChildrenMap();
3666 }
3667 
3668 //==============================================================================
3671  const ConfigurationTree& /*node*/, const std::string& /*startPath*/) const
3674 {
3675  std::string path = "/";
3676  return path;
3677 } // end getFirstPathToNode()
3678 
3679 //==============================================================================
3685 std::vector<std::pair<std::string, ConfigurationTree>> ConfigurationManager::getChildren(
3686  std::map<std::string, TableVersion>* memberMap,
3687  std::string* accumulatedTreeErrors) const
3688 {
3689  std::vector<std::pair<std::string, ConfigurationTree>> retVector;
3690 
3691  // if(accumulatedTreeErrors)
3692  // *accumulatedTreeErrors = "";
3693 
3694  bool filtering = memberMap && memberMap->size();
3695 
3696  //from root node, want active tables:
3697  for(auto& tablePair : nameToTableMap_)
3698  {
3699  if(filtering)
3700  {
3701  //if not in member map, ignore
3702  if(memberMap->find(tablePair.first) == memberMap->end())
3703  continue;
3704 
3705  //if in member map, and not active - that is a problem!
3706  try
3707  {
3708  if(!tablePair.second->isActive())
3709  {
3710  __SS__ << "Get Children with member map requires a child '"
3711  << tablePair.first << "' that is not active!" << __E__;
3712  __SS_THROW__;
3713  }
3714  }
3715  catch(const std::runtime_error& e)
3716  {
3717  if(accumulatedTreeErrors)
3718  {
3719  *accumulatedTreeErrors += e.what();
3720  __GEN_COUT_ERR__ << "Skipping " << tablePair.first
3721  << " since the table "
3722  "is not active."
3723  << __E__;
3724  continue;
3725  }
3726  throw;
3727  }
3728  }
3729 
3730  if(!tablePair.second->isActive()) // only consider if active
3731  continue;
3732 
3733  ConfigurationTree newNode(this, tablePair.second);
3734  if(accumulatedTreeErrors) // check for disconnects
3735  {
3736  try
3737  {
3738  std::vector<std::pair<std::string, ConfigurationTree>> newNodeChildren =
3739  newNode.getChildren();
3740  for(auto& newNodeChild : newNodeChildren)
3741  {
3742  if(newNodeChild.second.getTableName() ==
3743  ConfigurationManager::DESKTOP_ICON_TABLE_NAME &&
3744  !newNodeChild.second.isEnabled())
3745  continue; //skip check for Desktop Icons that are disabled.
3746 
3747  std::vector<std::pair<std::string, ConfigurationTree>>
3748  twoDeepChildren = newNodeChild.second.getChildren();
3749 
3750  for(auto& twoDeepChild : twoDeepChildren)
3751  {
3752  //__GEN_COUT__ << tablePair.first << " " <<
3753  // newNodeChild.first << " " << twoDeepChild.first
3754  // << __E__;
3755  if(twoDeepChild.second.isLinkNode() &&
3756  twoDeepChild.second.isDisconnected() &&
3757  twoDeepChild.second.getDisconnectedTableName() !=
3758  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
3759  {
3760  __SS__ << "At node '" + tablePair.first +
3761  "' with entry UID '" + newNodeChild.first +
3762  "' there is a disconnected child node at link "
3763  "column '" +
3764  twoDeepChild.first + "'" +
3765  " that points to table named '" +
3766  twoDeepChild.second.getDisconnectedTableName() +
3767  "' ...";
3768  *accumulatedTreeErrors += ss.str();
3769  }
3770  }
3771  }
3772  }
3773  catch(std::runtime_error& e)
3774  {
3775  __SS__ << "At node '" + tablePair.first +
3776  "' error detected descending through children:\n" +
3777  e.what();
3778  *accumulatedTreeErrors += ss.str();
3779  }
3780  } // done checking for disconnects
3781 
3782  retVector.push_back(
3783  std::pair<std::string, ConfigurationTree>(tablePair.first, newNode));
3784  } //end active table loop
3785 
3786  return retVector;
3787 } // end getChildren()
3788 
3789 //==============================================================================
3795 std::map<std::string /* childName */, ConfigurationTree>
3796 ConfigurationManager::getChildrenMap(std::map<std::string, TableVersion>* memberMap,
3797  std::string* accumulatedTreeErrors) const
3798 {
3799  std::map<std::string /* childName */, ConfigurationTree> retMap;
3800 
3801  // if(accumulatedTreeErrors)
3802  // *accumulatedTreeErrors = "";
3803 
3804  bool filtering = memberMap && memberMap->size();
3805 
3806  //from root node, want active tables:
3807  for(auto& tablePair : nameToTableMap_)
3808  {
3809  if(filtering)
3810  {
3811  //if not in member map, ignore
3812  if(memberMap->find(tablePair.first) == memberMap->end())
3813  continue;
3814 
3815  //if in member map, and not active - that is a problem!
3816  try
3817  {
3818  if(!tablePair.second->isActive())
3819  {
3820  __SS__ << "Get Children with member map requires a child '"
3821  << tablePair.first << "' that is not active!" << __E__;
3822  __SS_THROW__;
3823  }
3824  }
3825  catch(const std::runtime_error& e)
3826  {
3827  if(accumulatedTreeErrors)
3828  {
3829  *accumulatedTreeErrors += e.what();
3830  __GEN_COUT_ERR__ << "Skipping " << tablePair.first
3831  << " since the table "
3832  "is not active."
3833  << __E__;
3834  continue;
3835  }
3836  throw;
3837  }
3838  }
3839 
3840  if(!tablePair.second->isActive()) // only consider if active
3841  continue;
3842 
3843  ConfigurationTree newNode(this, tablePair.second);
3844  if(accumulatedTreeErrors) // check for disconnects
3845  {
3846  try
3847  {
3848  std::vector<std::pair<std::string, ConfigurationTree>> newNodeChildren =
3849  newNode.getChildren();
3850  for(auto& newNodeChild : newNodeChildren)
3851  {
3852  if(newNodeChild.second.getTableName() ==
3853  ConfigurationManager::DESKTOP_ICON_TABLE_NAME &&
3854  !newNodeChild.second.isEnabled())
3855  continue; //skip check for Desktop Icons that are disabled.
3856 
3857  std::vector<std::pair<std::string, ConfigurationTree>>
3858  twoDeepChildren = newNodeChild.second.getChildren();
3859 
3860  for(auto& twoDeepChild : twoDeepChildren)
3861  {
3862  //__GEN_COUT__ << tablePair.first << " " <<
3863  // newNodeChild.first << " " << twoDeepChild.first
3864  // << __E__;
3865  if(twoDeepChild.second.isLinkNode() &&
3866  twoDeepChild.second.isDisconnected() &&
3867  twoDeepChild.second.getDisconnectedTableName() !=
3868  TableViewColumnInfo::DATATYPE_LINK_DEFAULT)
3869  {
3870  __SS__ << "At node '" + tablePair.first +
3871  "' with entry UID '" + newNodeChild.first +
3872  "' there is a disconnected child node at link "
3873  "column '" +
3874  twoDeepChild.first + "'" +
3875  " that points to table named '" +
3876  twoDeepChild.second.getDisconnectedTableName() +
3877  "' ...";
3878  *accumulatedTreeErrors += ss.str();
3879  }
3880  }
3881  }
3882  }
3883  catch(std::runtime_error& e)
3884  {
3885  __SS__ << "At node '" + tablePair.first +
3886  "' error detected descending through children:\n" +
3887  e.what();
3888  *accumulatedTreeErrors += ss.str();
3889  }
3890  } // done checking for disconnects
3891 
3892  retMap.emplace(
3893  std::pair<std::string, ConfigurationTree>(tablePair.first, newNode));
3894  } //end active table loop
3895 
3896  return retMap;
3897 } // end getChildrenMap()
3898 
3899 //==============================================================================
3904 const TableBase* ConfigurationManager::getTableByName(const std::string& tableName) const
3905 {
3906  std::map<std::string, TableBase*>::const_iterator it;
3907  if((it = nameToTableMap_.find(tableName)) == nameToTableMap_.end())
3908  {
3909  __SS__ << "Cannot find table named '" << tableName
3910  << "' - you need to load the table before it can be used.";
3911 
3912  if(nameToTableMap_.size() == 0)
3913  ss << "\n\nAll tables are missing. Your configuration database connection "
3914  "may have been interrupted. Did an ssh tunnel disconnect?"
3915  << __E__;
3916  else
3917  {
3918  if(tableName == XDAQ_CONTEXT_TABLE_NAME)
3919  ss << "\n\nThe XDAQ Context Table is essential to the operation of ots. "
3920  "Without it, ots can not determine which applications are running "
3921  "on which hosts. Make sure that you have loaded a valid "
3922  "Configuration Context group that contains the XDAQ Context "
3923  "Table."
3924  << __E__;
3925  else
3926  ss << " It is likely missing from the member list of the Table "
3927  "Group that was loaded."
3928  << __E__;
3929 
3930  ss << "\nYou may need to enter wiz mode to remedy the situation, use the "
3931  "following:\n"
3932  "\n\t ots --wiz"
3933  "\n\n\n"
3934  << __E__;
3935 
3936  ss << __E__ << StringMacros::stackTrace() << __E__;
3937  }
3938 
3939  __SS_ONLY_THROW__;
3940  }
3941  TLOG_DEBUG(55) << "Table " << tableName << " is at "
3942  << static_cast<void*>(it->second);
3943  return it->second;
3944 } // end getTableByName()
3945 
3946 //==============================================================================
3951 {
3952  if(!theBackboneTableGroupKey_) // no active backbone
3953  {
3954  __GEN_COUT_WARN__ << "getTableGroupKey() Failed! No active backbone currently."
3955  << __E__;
3956  return TableGroupKey();
3957  }
3958 
3959  // may already be loaded, but that's ok, load anyway to be sure
3960  loadTableGroup(theBackboneTableGroup_, *theBackboneTableGroupKey_);
3961 
3962  return *theBackboneTableGroupKey_;
3963 } // end loadConfigurationBackbone()
3964 
3966 //==============================================================================
3978 std::pair<std::string, TableGroupKey> ConfigurationManager::getTableGroupFromAlias(
3979  std::string systemAlias, ProgressBar* progressBar)
3980 {
3981  // steps
3982  // check if special alias
3983  // if so, parse and return name/key
3984  // else, load active backbone
3985  // find runType in Group Aliases table
3986  // return key
3987 
3988  if(progressBar)
3989  progressBar->step();
3990 
3991  if(systemAlias.find("GROUP:") == 0)
3992  {
3993  if(progressBar)
3994  progressBar->step();
3995 
3996  unsigned int i = strlen("GROUP:");
3997  unsigned int j = systemAlias.find(':', i);
3998 
3999  if(progressBar)
4000  progressBar->step();
4001  if(j > i) // success
4002  return std::pair<std::string, TableGroupKey>(
4003  systemAlias.substr(i, j - i), TableGroupKey(systemAlias.substr(j + 1)));
4004  else // failure
4005  return std::pair<std::string, TableGroupKey>("", TableGroupKey());
4006  }
4007 
4009 
4010  if(progressBar)
4011  progressBar->step();
4012 
4013  try
4014  {
4015  // find runType in Group Aliases table
4016  ConfigurationTree entry =
4017  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getNode(systemAlias);
4018 
4019  if(progressBar)
4020  progressBar->step();
4021 
4022  return std::pair<std::string, TableGroupKey>(
4023  entry.getNode("GroupName").getValueAsString(),
4024  TableGroupKey(entry.getNode("GroupKey").getValueAsString()));
4025  }
4026  catch(...)
4027  {
4028  }
4029 
4030  // on failure, here
4031 
4032  if(progressBar)
4033  progressBar->step();
4034 
4035  return std::pair<std::string, TableGroupKey>("", TableGroupKey());
4036 } // end getTableGroupFromAlias()
4037 
4038 //==============================================================================
4041 std::map<std::string /*groupAlias*/, std::pair<std::string /*groupName*/, TableGroupKey>>
4043 {
4045  false /* throwErrors */,
4046  "" /* pathToActiveGroupsFile */,
4047  ConfigurationManager::LoadGroupType::
4048  ONLY_BACKBONE_TYPE); // make sure the active configuration backbone is
4049  // loaded from disk (i.e. the latest activated at the ConfigurationGUISupervisor)!
4050 
4051  std::map<std::string /*groupAlias*/,
4052  std::pair<std::string /*groupName*/, TableGroupKey>>
4053  retMap;
4054 
4055  std::vector<std::pair<std::string, ConfigurationTree>> entries =
4056  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getChildren();
4057  for(auto& entryPair : entries)
4058  {
4059  retMap[entryPair.first] = std::pair<std::string, TableGroupKey>(
4060  entryPair.second.getNode("GroupName").getValueAsString(),
4061  TableGroupKey(entryPair.second.getNode("GroupKey").getValueAsString()));
4062  }
4063  return retMap;
4064 } // end getActiveGroupAliases()
4065 
4066 //==============================================================================
4069 std::set<std::pair<std::string /*table name*/, TableVersion /*aliased version*/>>
4070 ConfigurationManager::getVersionAliases(const std::string& tableAliasNeedle) const
4071 {
4072  std::set<std::pair<std::string /*table name*/, TableVersion /*aliased version*/>>
4073  retSet;
4074 
4075  auto tableAliasMap = getVersionAliases();
4076 
4077  for(auto& tableAliasMap : tableAliasMap)
4078  for(auto& tableAliasPair : tableAliasMap.second)
4079  if(tableAliasPair.first == tableAliasNeedle) //then table alias match!
4080  retSet.insert(std::pair<std::string /*table name*/,
4081  TableVersion /*aliased version*/>(
4082  tableAliasMap.first, tableAliasPair.second));
4083 
4084  return retSet;
4085 } //end getVersionAliases()
4086 
4087 //==============================================================================
4090 std::map<std::string /*table name*/,
4091  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
4093 {
4094  //__GEN_COUT__ << "getVersionAliases()" << __E__;
4095 
4096  std::map<std::string /*table name*/,
4097  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
4098  retMap;
4099 
4100  std::map<std::string, TableVersion> activeVersions = getActiveVersions();
4101  std::string versionAliasesTableName =
4102  ConfigurationManager::VERSION_ALIASES_TABLE_NAME;
4103  if(activeVersions.find(versionAliasesTableName) == activeVersions.end())
4104  {
4105  __SS__ << "Active version of VersionAliases missing!"
4106  << " Make sure you have a valid active Backbone Group." << __E__;
4107  __GEN_COUT_WARN__ << "\n" << ss.str();
4108  return retMap;
4109  }
4110 
4111  //__GEN_COUT__ << "activeVersions[\"" << versionAliasesTableName << "\"]=" << activeVersions[versionAliasesTableName] << __E__;
4112 
4113  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
4114  getNode(versionAliasesTableName).getChildren();
4115 
4116  // create map
4117  // add the first of each tableName, versionAlias pair encountered
4118  // ignore any repeats (Note: this also prevents overwriting of Scratch alias)
4119  std::string tableName, versionAlias;
4120  for(auto& aliasNodePair : aliasNodePairs)
4121  {
4122  tableName = aliasNodePair.second.getNode("TableName").getValueAsString();
4123  versionAlias = aliasNodePair.second.getNode("VersionAlias").getValueAsString();
4124 
4125  if(retMap.find(tableName) != retMap.end() &&
4126  retMap[tableName].find(versionAlias) != retMap[tableName].end())
4127  continue; // skip repeats (Note: this also prevents overwriting of Scratch
4128  // alias)
4129 
4130  // validate that SubsystemCommonContext aliases only reference Context group tables
4131  if(versionAlias == SUBSYSTEM_COMMON_CONTEXT_VERSION_ALIAS ||
4132  versionAlias == SUBSYSTEM_COMMON_CONTEXT_OVERRIDE_VERSION_ALIAS)
4133  {
4134  if(fixedContextMemberNames_.find(tableName) == fixedContextMemberNames_.end())
4135  {
4136  __SS__ << "Version alias '" << versionAlias << "' for table '"
4137  << tableName << "' is invalid! '" << versionAlias
4138  << "' aliases may only reference Context group tables. "
4139  << "Valid Context group tables are: "
4140  << StringMacros::setToString(fixedContextMemberNames_) << __E__;
4141  __SS_THROW__;
4142  }
4143  }
4144 
4145  // else add version to map
4146  retMap[tableName][versionAlias] =
4147  TableVersion(aliasNodePair.second.getNode("Version").getValueAsString());
4148  }
4149 
4150  return retMap;
4151 } // end getVersionAliases()
4152 
4153 //==============================================================================
4160  const std::map<std::string /*tableName*/, TableVersion>& mergeInTables,
4161  const std::map<std::string /*tableName*/, TableVersion>& overrideTables)
4162 {
4163  __GEN_COUT__ << "Applying Context Common Tables..." << __E__;
4164 
4165  if(overrideTables.size())
4166  {
4167  __GEN_COUT__ << "Context overriding tables: "
4168  << StringMacros::mapToString(overrideTables) << __E__;
4169 
4170  std::map<std::pair<std::string, std::string>, std::string> uidConversionMap;
4171  std::map<std::pair<std::string, std::pair<std::string, std::string>>, std::string>
4172  groupidConversionMap;
4173 
4174  for(const auto& overridePair : overrideTables)
4175  {
4176  if(nameToTableMap_.find(overridePair.first) == nameToTableMap_.end())
4177  {
4178  __GEN_COUT__ << "Skipping context override of table '"
4179  << overridePair.first << "-v" << overridePair.second
4180  << "' which is not loaded." << __E__;
4181  continue;
4182  }
4183 
4184  TableVersion activeVersion =
4185  nameToTableMap_.at(overridePair.first)->getView().getVersion();
4186  __GEN_COUT__ << "Context overriding table '" << overridePair.first << "' v"
4187  << activeVersion << " with version v" << overridePair.second
4188  << __E__;
4189 
4190  std::stringstream mergeReport;
4191  TableVersion newVersion =
4192  nameToTableMap_.at(overridePair.first)
4193  ->mergeViews(
4194  getVersionedTableByName(overridePair.first, activeVersion)
4195  ->getView(),
4196  getVersionedTableByName(overridePair.first, overridePair.second)
4197  ->getView(),
4198  TableVersion(),
4199  "context-override-table",
4200  TableBase::MergeApproach::REPLACE,
4201  uidConversionMap,
4202  groupidConversionMap,
4203  false /* fillRecordConversionMaps */,
4204  true /* applyRecordConversionMaps */,
4205  false /* generateUniqueDataColumns */,
4206  &mergeReport);
4207 
4208  nameToTableMap_.at(overridePair.first)->setActiveView(newVersion);
4209  __GEN_COUT__ << "Context override applied: '" << overridePair.first
4210  << "' resulting version v" << newVersion << __E__;
4211  }
4212  }
4213 
4214  if(mergeInTables.size())
4215  {
4216  __GEN_COUT__ << "Context merging-in tables: "
4217  << StringMacros::mapToString(mergeInTables) << __E__;
4218 
4219  std::map<std::pair<std::string, std::string>, std::string> uidConversionMap;
4220  std::map<std::pair<std::string, std::pair<std::string, std::string>>, std::string>
4221  groupidConversionMap;
4222 
4223  for(const auto& mergeInPair : mergeInTables)
4224  {
4225  if(overrideTables.find(mergeInPair.first) != overrideTables.end())
4226  continue;
4227 
4228  if(nameToTableMap_.find(mergeInPair.first) == nameToTableMap_.end())
4229  {
4230  __GEN_COUT__ << "Skipping context merge-in of table '"
4231  << mergeInPair.first << "-v" << mergeInPair.second
4232  << "' which is not loaded." << __E__;
4233  continue;
4234  }
4235 
4236  TableVersion activeVersion =
4237  nameToTableMap_.at(mergeInPair.first)->getView().getVersion();
4238  __GEN_COUT__ << "Context merging-in table '" << mergeInPair.first << "' v"
4239  << activeVersion << " with version v" << mergeInPair.second
4240  << __E__;
4241 
4242  std::stringstream mergeReport;
4243  TableVersion newVersion =
4244  nameToTableMap_.at(mergeInPair.first)
4245  ->mergeViews(
4246  getVersionedTableByName(mergeInPair.first, activeVersion)
4247  ->getView(),
4248  getVersionedTableByName(mergeInPair.first, mergeInPair.second)
4249  ->getView(),
4250  TableVersion(),
4251  "context-merge-in-table",
4252  TableBase::MergeApproach::SKIP,
4253  uidConversionMap,
4254  groupidConversionMap,
4255  false /* fillRecordConversionMaps */,
4256  true /* applyRecordConversionMaps */,
4257  false /* generateUniqueDataColumns */,
4258  &mergeReport);
4259 
4260  nameToTableMap_.at(mergeInPair.first)->setActiveView(newVersion);
4261  __GEN_COUT__ << "Context merge-in applied: '" << mergeInPair.first
4262  << "' resulting version v" << newVersion << __E__;
4263  }
4264  }
4265 
4266  __GEN_COUT__ << "Done applying Context Common Tables." << __E__;
4267 } // end applyContextCommonTables()
4268 
4269 //==============================================================================
4271 std::map<std::string, TableVersion> ConfigurationManager::getActiveVersions(void) const
4272 {
4273  std::map<std::string, TableVersion> retMap;
4274  for(auto& table : nameToTableMap_)
4275  {
4276  __GEN_COUTS__(2) << table.first << __E__;
4277 
4278  // check configuration pointer is not null and that there is an active view
4279  if(table.second && table.second->isActive())
4280  {
4281  __GEN_COUTS__(2) << table.first << "_v" << table.second->getViewVersion()
4282  << __E__;
4283  retMap.insert(std::pair<std::string, TableVersion>(
4284  table.first, table.second->getViewVersion()));
4285  }
4286  }
4287 
4288  return retMap;
4289 } // end getActiveVersions()
4290 
4293 //{
4294 //
4295 // //fixme/todo this is called before setupAll so it breaks!
4296 // //====================================================
4297 // const DetectorConfiguration* detectorConfiguration =
4298 //__GET_CONFIG__(DetectorConfiguration); for(auto& type :
4299 // detectorConfiguration->getDetectorTypes()) theDACsConfigurations_[type] =
4300 //(DACsTableBase*)(getTableByName(type + "DACsConfiguration"));
4301 // //====================================================
4302 //
4303 // theDACStreams_[fecName].makeStream(fecName,
4304 // __GET_CONFIG__(DetectorConfiguration),
4305 // __GET_CONFIG__(DetectorToFEConfiguration),
4306 // theDACsConfigurations_,
4307 // __GET_CONFIG__(MaskConfiguration));//, theTrimConfiguration_);
4308 //
4309 // __GEN_COUT__ << "Done with DAC stream!" << __E__;
4310 // return theDACStreams_[fecName];
4311 //}
4312 
4313 //==============================================================================
4314 std::shared_ptr<TableGroupKey> ConfigurationManager::makeTheTableGroupKey(
4315  TableGroupKey key)
4316 {
4317  if(theConfigurationTableGroupKey_)
4318  {
4319  if(*theConfigurationTableGroupKey_ != key)
4321  else
4322  return theConfigurationTableGroupKey_;
4323  }
4324  return std::shared_ptr<TableGroupKey>(new TableGroupKey(key));
4325 } // end makeTheTableGroupKey()
4326 
4327 //==============================================================================
4328 const std::set<std::string>& ConfigurationManager::getActiveContextMemberNames()
4329 {
4330  //copy fixed context tables, then add optional tables if active
4331  contextMemberNames_ = ConfigurationManager::fixedContextMemberNames_;
4332 
4333  auto it =
4334  nameToTableMap_.find(ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE);
4335  if(it == nameToTableMap_.end())
4336  return contextMemberNames_;
4337 
4338  if(!it->second->isActive()) //if optional table is active, add it
4339  {
4340  contextMemberNames_.emplace(
4341  ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE);
4342  }
4343  return contextMemberNames_;
4344 } // end getContextMemberNames()
4345 
4346 //==============================================================================
4347 const std::set<std::string>& ConfigurationManager::getFixedContextMemberNames()
4348 {
4349  return ConfigurationManager::fixedContextMemberNames_;
4350 } // end getContextMemberNames()
4351 
4352 //==============================================================================
4353 const std::set<std::string>& ConfigurationManager::getBackboneMemberNames()
4354 {
4355  return ConfigurationManager::backboneMemberNames_;
4356 } // end getBackboneMemberNames()
4357 
4358 //==============================================================================
4359 const std::set<std::string>& ConfigurationManager::getIterateMemberNames()
4360 {
4361  return ConfigurationManager::iterateMemberNames_;
4362 } // end getIterateMemberNames()
4363 
4364 //==============================================================================
4365 const std::set<std::string>& ConfigurationManager::getConfigurationMemberNames(void)
4366 {
4367  configurationMemberNames_.clear();
4368 
4369  std::map<std::string, TableVersion> activeTables = getActiveVersions();
4370 
4371  for(auto& tablePair : activeTables)
4372  if(
4373  //check if not context table
4374  ConfigurationManager::fixedContextMemberNames_.find(tablePair.first) ==
4375  ConfigurationManager::fixedContextMemberNames_.end() &&
4376  tablePair.first != ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE &&
4377 
4378  //check if not backbone table
4379  ConfigurationManager::backboneMemberNames_.find(tablePair.first) ==
4380  ConfigurationManager::backboneMemberNames_.end() &&
4381 
4382  //check if not iterate table
4383  ConfigurationManager::iterateMemberNames_.find(tablePair.first) ==
4384  ConfigurationManager::iterateMemberNames_.end())
4385  {
4386  // else, it is a configuration table
4387  configurationMemberNames_.emplace(tablePair.first);
4388  }
4389 
4390  return configurationMemberNames_;
4391 } // end getConfigurationMemberNames()
4392 
4393 //==============================================================================
4394 void ConfigurationManager::initializeFromFhicl(const std::string& fhiclPath)
4395 {
4396  __GEN_COUT__ << "Initializing from fhicl: " << fhiclPath << __E__;
4397 
4398  // https://cdcvs.fnal.gov/redmine/projects/fhicl-cpp/wiki
4399 
4400  // LoadParameterSet() ... from $ARTDAQ_INC/artdaq/Application/LoadParameterSet.hh
4401  fhicl::ParameterSet pset = LoadParameterSet(fhiclPath);
4402 
4403  if(pset.get_names().size() == 0)
4404  {
4405  __GEN_SS__ << "Empty fcl configuration parameter set found! File: " << fhiclPath
4406  << __E__;
4407  __SS_THROW__;
4408  }
4409 
4410  //===========================
4411  // fcl should be FE record(s):
4412  // interface0: {
4413  // FEInterfacePluginName: "FEOtsUDPTemplateInterface"
4414  // LinkToFETypeTable_FEOtsUDPTemplateInterfaceTable: {
4415  // OtsInterface0: {
4416  // InterfaceIPAddress: "127.0.0.1"
4417  // InterfacePort: 4000
4418  // HostIPAddress: "127.0.0.1"
4419  // HostPort: 4020
4420  // StreamToIPAddress: "127.0.0.1"
4421  // StreamToPort: 4021
4422  // }
4423  // } //end FEOtsUDPTemplateInterfaceTable link record
4424  // } //end interface0
4425  //===========================
4426 
4427  // Steps:
4428  // Create one context with one FE supervisor
4429  // and one/many FEs specified by fcl
4430  //
4431 
4432  TableBase* table;
4433 
4434  // create context and add context record
4435  {
4436  table = 0;
4437  theInterface_->get(table, // configurationPtr
4438  ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME, // tableName
4439  0, // groupKey
4440  0, // groupName
4441  true // dontFill=false to fill
4442  );
4443 
4444  nameToTableMap_[ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME] = table;
4445 
4446  table->setupMockupView(TableVersion(TableVersion::DEFAULT));
4447  table->setActiveView(TableVersion(TableVersion::DEFAULT));
4448 
4449  TableView* view = table->getViewP();
4450  __GEN_COUT__ << "Activated version: " << view->getVersion() << __E__;
4451 
4452  // add context record ---------------------
4453  view->addRow();
4454  auto colMap = view->getColumnNamesMap();
4455 
4456  view->setValue("MacroMakerFEContext", 0, colMap["ContextUID"]);
4457  view->setValue("XDAQApplicationTable", 0, colMap["LinkToApplicationTable"]);
4458  view->setValue("MacroMakerFEContextApps", 0, colMap["LinkToApplicationGroupID"]);
4459  view->setValue("1", 0, colMap[TableViewColumnInfo::COL_NAME_STATUS]);
4460 
4461  __GEN_COUT__ << "Done adding context record..." << __E__;
4462  if(TTEST(1))
4463  {
4464  std::stringstream ss;
4465  view->print(ss);
4466  __GEN_COUTT__ << "view->print()" << ss.str() << __E__;
4467  }
4468 
4469  } // done with context record
4470 
4471  // create app table and add application record
4472  {
4473  table = 0;
4474  theInterface_->get(
4475  table, // configurationPtr
4476  ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME, // tableName
4477  0, // groupKey
4478  0, // groupName
4479  true // dontFill=false to fill
4480  );
4481 
4482  nameToTableMap_[ConfigurationManager::XDAQ_APPLICATION_TABLE_NAME] = table;
4483 
4484  table->setupMockupView(TableVersion(TableVersion::DEFAULT));
4485  table->setActiveView(TableVersion(TableVersion::DEFAULT));
4486 
4487  TableView* view = table->getViewP();
4488  __GEN_COUT__ << "Activated version: " << view->getVersion() << __E__;
4489 
4490  // add application record ---------------------
4491  view->addRow();
4492  auto colMap = view->getColumnNamesMap();
4493 
4494  view->setValue("MacroMakerFEContextApps", 0, colMap["ApplicationGroupID"]);
4495  view->setValue("MacroMakerFESupervisor", 0, colMap["ApplicationUID"]);
4496  view->setValue("FESupervisorTable", 0, colMap["LinkToSupervisorTable"]);
4497  view->setValue("MacroMakerFESupervisor", 0, colMap["LinkToSupervisorUID"]);
4498  view->setValue("1", 0, colMap[TableViewColumnInfo::COL_NAME_STATUS]);
4499  view->setValue(__ENV__("FE_SUPERVISOR_ID"), 0, colMap["Id"]); // XDAQ LID
4500 
4501  __GEN_COUT__ << "Done adding application record..." << __E__;
4502  if(TTEST(1))
4503  {
4504  std::stringstream ss;
4505  view->print(ss);
4506  __GEN_COUTT__ << "view->print()" << ss.str() << __E__;
4507  }
4508  } // done with app record
4509 
4510  // create FE Supervisor table and Supervisor record
4511  {
4512  table = 0;
4513  theInterface_->get(table, // configurationPtr
4514  "FESupervisorTable", // tableName
4515  0, // groupKey
4516  0, // groupName
4517  true // dontFill=false to fill
4518  );
4519 
4520  nameToTableMap_["FESupervisorTable"] = table;
4521 
4522  table->setupMockupView(TableVersion(TableVersion::DEFAULT));
4523  table->setActiveView(TableVersion(TableVersion::DEFAULT));
4524 
4525  TableView* view = table->getViewP();
4526  __GEN_COUT__ << "Activated version: " << view->getVersion() << __E__;
4527 
4528  // add application record ---------------------
4529  view->addRow();
4530  auto colMap = view->getColumnNamesMap();
4531 
4532  view->setValue("MacroMakerFESupervisor", 0, colMap["SupervisorUID"]);
4533  view->setValue("FEInterfaceTable", 0, colMap["LinkToFEInterfaceTable"]);
4534  view->setValue(
4535  "MacroMakerFESupervisorInterfaces", 0, colMap["LinkToFEInterfaceGroupID"]);
4536 
4537  __GEN_COUT__ << "Done adding supervisor record..." << __E__;
4538  if(TTEST(1))
4539  {
4540  std::stringstream ss;
4541  view->print(ss);
4542  __GEN_COUTT__ << "view->print()" << ss.str() << __E__;
4543  }
4544  } // done with app record
4545 
4546  // create FE Interface table and interface record(s)
4547  recursiveInitFromFhiclPSet("FEInterfaceTable" /*tableName*/,
4548  pset /*fhicl parameter set*/,
4549  "" /*uid*/,
4550  "MacroMakerFESupervisorInterfaces" /*groupID*/,
4551  "FE" /*childLinkIndex*/);
4552 
4553  // init every table after modifications
4554  for(auto& table : nameToTableMap_)
4555  {
4556  table.second->getViewP()->init();
4557  }
4558 
4559  // verify extraction
4560  if(0)
4561  {
4562  __GEN_COUT__ << "================================================" << __E__;
4563  nameToTableMap_["FESupervisorTable"]->getViewP()->print();
4564  nameToTableMap_["FEInterfaceTable"]->getViewP()->print();
4565 
4566  auto sups = getNode("FESupervisorTable").getChildrenNames();
4567  __GEN_COUT__ << "Supervisors extracted from fhicl: " << sups.size() << __E__;
4568  auto fes = getNode("FEInterfaceTable").getChildrenNames();
4569  __GEN_COUT__ << "Front-ends extracted from fhicl: " << fes.size() << __E__;
4570  {
4571  auto a = getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME);
4572  __GEN_COUTV__(a.getValueAsString());
4573 
4574  auto b = a.getNode("MacroMakerFEContext");
4575  __GEN_COUTV__(b.getValueAsString());
4576 
4577  auto c = b.getNode("LinkToApplicationTable");
4578  __GEN_COUTV__(c.getValueAsString());
4579 
4580  auto d = c.getNode("MacroMakerFESupervisor");
4581  __GEN_COUTV__(d.getValueAsString());
4582 
4583  auto e = d.getNode("LinkToSupervisorTable");
4584  __GEN_COUTV__(e.getValueAsString());
4585 
4586  auto f = e.getNode("LinkToFEInterfaceTable");
4587  __GEN_COUTV__(f.getValueAsString());
4588 
4589  auto z = f.getChildrenNames();
4590  __GEN_COUTV__(StringMacros::vectorToString(z));
4591  __GEN_COUTV__(z.size());
4592  auto y = f.getChildrenNames(false /*byPriority*/, true /*onlyStatusTrue*/);
4593  __GEN_COUTV__(StringMacros::vectorToString(y));
4594  __GEN_COUTV__(y.size());
4595  auto x = f.getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/);
4596  __GEN_COUTV__(StringMacros::vectorToString(x));
4597  __GEN_COUTV__(x.size());
4598 
4599  auto g = f.getNode("dtc0");
4600  __GEN_COUTV__(g.getValueAsString());
4601  auto h = f.getNode("interface0");
4602  __GEN_COUTV__(h.getValueAsString());
4603 
4604  auto fes =
4605  getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME)
4606  .getNode(
4607  "MacroMakerFEContext/LinkToApplicationTable/"
4608  "MacroMakerFESupervisor/LinkToSupervisorTable")
4609  .getNode("LinkToFEInterfaceTable")
4610  .getChildrenNames(true /*byPriority*/, true /*onlyStatusTrue*/);
4611  __GEN_COUTV__(fes.size());
4612  __GEN_COUTV__(StringMacros::vectorToString(fes));
4613  }
4614  }
4615 
4616 } // end initializeFromFhicl()
4617 
4618 //==============================================================================
4623 void ConfigurationManager::recursiveInitFromFhiclPSet(const std::string& tableName,
4624  const fhicl::ParameterSet& pset,
4625  const std::string& recordName,
4626  const std::string& groupName,
4627  const std::string& groupLinkIndex)
4628 {
4629  __GEN_COUTT__ << "recursiveInitFromFhiclPSet() "
4630  << "Adding table '" << tableName << "' record(s)..." << __E__;
4631 
4632  TableBase* table;
4633  // create context and add context record
4634  {
4635  table = 0;
4636  if(nameToTableMap_.find(tableName) == nameToTableMap_.end())
4637  {
4638  __GEN_COUTT__ << "Table not found, so making '" << tableName
4639  << "' instance..." << __E__;
4640  theInterface_->get(table, // configurationPtr
4641  tableName, // tableName
4642  0, // groupKey
4643  0, // groupName
4644  true // dontFill=false to fill
4645  );
4646 
4647  nameToTableMap_[tableName] = table;
4648  table->setupMockupView(TableVersion(TableVersion::DEFAULT));
4649  }
4650  else
4651  {
4652  __GEN_COUTT__ << "Existing table found, so using '" << tableName
4653  << "'instance..." << __E__;
4654  table = nameToTableMap_[tableName];
4655  }
4656 
4657  table->setActiveView(TableVersion(TableVersion::DEFAULT));
4658 
4659  TableView* view = table->getViewP();
4660  __GEN_COUTT__ << "Activated version: " << view->getVersion() << __E__;
4661  // view->print();
4662 
4663  if(recordName != "") // then add this record
4664  {
4665  // Steps:
4666  // - add row
4667  // - set UID and enable (if possible)
4668  // - set values for parameter columns
4669  // - define links
4670 
4671  __GEN_COUTTV__(recordName);
4672 
4673  // add row and get column map
4674  unsigned int r = view->addRow();
4675  auto colMap = view->getColumnNamesMap();
4676 
4677  // set UID and enable (if possible)
4678  view->setValue(recordName, r, view->getColUID());
4679  try
4680  {
4681  view->setValue("1", r, view->getColStatus());
4682  }
4683  catch(...)
4684  {
4685  __GEN_COUTT__ << "No status column to set for '" << recordName << "'"
4686  << __E__;
4687  }
4688 
4689  if(groupName != "") // then set groupID for this record
4690  {
4691  __GEN_COUTT__ << "Setting group ID for group link index '"
4692  << groupLinkIndex << "'" << __E__;
4693 
4694  int groupIDCol = view->getLinkGroupIDColumn(groupLinkIndex);
4695  __GEN_COUTT__ << "Setting group ID for group link index '"
4696  << groupLinkIndex << "' at column " << groupIDCol << " to '"
4697  << groupName << ".'" << __E__;
4698 
4699  view->setValue(groupName, r, groupIDCol);
4700  }
4701 
4702  // then set parameters
4703  auto names = pset.get_names();
4704  for(const auto& colName : names)
4705  {
4706  if(!pset.is_key_to_atom(colName))
4707  continue;
4708 
4709  auto colIt = colMap.find(colName);
4710  if(colIt == colMap.end())
4711  {
4712  __SS__ << "Field '" << colName << "' of record '" << recordName
4713  << "' in table '" << tableName << "' was not found in columns."
4714  << "\n\nHere are the existing column names:\n";
4715  unsigned int i = 0;
4716  for(const auto& col : colMap)
4717  ss << "\n" << ++i << ".\t" << col.first;
4718  ss << __E__;
4719  __SS_THROW__;
4720  }
4721  // skip overwriting group ID - already setup by parent group link
4722  if(view->getColumnInfo(colIt->second).isGroupID())
4723  continue;
4724 
4725  const std::string value = pset.get<std::string>(colName);
4726  __GEN_COUTT__ << "Setting '" << recordName << "' parameter at column "
4727  << colIt->second << ", '" << colName << "'\t = " << value
4728  << __E__;
4729  view->setValueAsString(value, r, colIt->second);
4730  } // end set parameters
4731 
4732  // then define links
4733  for(const auto& linkName : names)
4734  {
4735  if(pset.is_key_to_atom(linkName))
4736  continue;
4737 
4738  __GEN_COUTTV__(linkName);
4739 
4740  // split into column name and table
4741  unsigned int c = linkName.size() - 1;
4742  for(; c >= 1; --c)
4743  if(linkName[c] == '_') // find first underscore to split linkName
4744  break;
4745 
4746  if(c == 0)
4747  {
4748  __SS__ << "Illegal link name '" << linkName
4749  << "' found. The format must be <Column name>_<Target table "
4750  "name>,.. for example '"
4751  << "LinkToFETypeTable_FEOtsUDPTemplateInterfaceTable'"
4752  << __E__;
4753  __SS_THROW__;
4754  }
4755  std::string colName = linkName.substr(0, c);
4756  __GEN_COUTTV__(colName);
4757 
4758  auto colIt = colMap.find(colName);
4759  if(colIt == colMap.end())
4760  {
4761  __SS__ << "Link '" << colName << "' of record '" << recordName
4762  << "' in table '" << tableName << "' was not found in columns."
4763  << "\n\nHere are the existing column names:\n";
4764  unsigned int i = 0;
4765  for(const auto& col : colMap)
4766  ss << "\n" << i << ".\t" << col.first << __E__;
4767  __SS_THROW__;
4768  }
4769  //__GEN_COUT__ << "Setting link at column " << colIt->second << __E__;
4770 
4771  std::pair<unsigned int /*link col*/, unsigned int /*link id col*/>
4772  linkPair;
4773  bool isGroupLink;
4774  view->getChildLink(colIt->second, isGroupLink, linkPair);
4775 
4776  //__GEN_COUTV__(isGroupLink);
4777  //__GEN_COUTV__(linkPair.first);
4778  //__GEN_COUTV__(linkPair.second);
4779 
4780  std::string linkTableName = linkName.substr(c + 1);
4781  __GEN_COUTTV__(linkTableName);
4782 
4783  auto linkPset = pset.get<fhicl::ParameterSet>(linkName);
4784  auto linkRecords = linkPset.get_pset_names();
4785  if(!isGroupLink && linkRecords.size() > 1)
4786  {
4787  __SS__ << "A Unique Link can only point to one record. "
4788  << "The specified link '" << colName << "' of record '"
4789  << recordName << "' in table '" << tableName << "' has "
4790  << linkRecords.size() << " children records specified. "
4791  << __E__;
4792  __SS_THROW__;
4793  }
4794 
4795  if(linkRecords.size() == 0)
4796  {
4797  __GEN_COUTT__ << "No child records, so leaving link disconnected."
4798  << __E__;
4799  continue;
4800  }
4801 
4802  __GEN_COUTT__ << "Setting Link at columns [" << linkPair.first << ","
4803  << linkPair.second << "]" << __E__;
4804  view->setValue(linkTableName, r, linkPair.first);
4805 
4806  if(!isGroupLink)
4807  {
4808  __GEN_COUTT__ << "Setting up Unique link to " << linkRecords[0]
4809  << __E__;
4810 
4811  view->setValue(linkRecords[0], r, linkPair.second);
4812 
4813  recursiveInitFromFhiclPSet(
4814  linkTableName /*tableName*/,
4815  linkPset.get<fhicl::ParameterSet>(
4816  linkRecords[0]) /*fhicl parameter set*/,
4817  linkRecords[0] /*uid*/,
4818  "" /*groupID*/);
4819  }
4820  else
4821  {
4822  std::string childLinkIndex =
4823  view->getColumnInfo(linkPair.first).getChildLinkIndex();
4824  std::string groupName = recordName + "Group";
4825 
4826  view->setValue(groupName, r, linkPair.second);
4827 
4828  for(const auto& groupRecord : linkRecords)
4829  {
4830  __GEN_COUTT__ << "Setting '" << childLinkIndex
4831  << "' Group link to '" << groupName << "' record '"
4832  << groupRecord << "'" << __E__;
4833 
4834  recursiveInitFromFhiclPSet(
4835  linkTableName /*tableName*/,
4836  linkPset.get<fhicl::ParameterSet>(
4837  groupRecord) /*fhicl parameter set*/,
4838  groupRecord /*uid*/,
4839  groupName /*groupID*/,
4840  childLinkIndex /*groupLinkIndex*/);
4841  }
4842  }
4843 
4844  } // end link handling
4845  }
4846  else if(groupName != "") // then add group of records
4847  {
4848  // get_pset_names();
4849  // get_names
4850  __GEN_COUTTV__(groupName);
4851  auto psets = pset.get_pset_names();
4852  for(const auto& ps : psets)
4853  {
4854  __GEN_COUTTV__(ps);
4855  recursiveInitFromFhiclPSet(
4856  tableName /*tableName*/,
4857  pset.get<fhicl::ParameterSet>(ps) /*fhicl parameter set*/,
4858  ps /*uid*/,
4859  groupName /*groupID*/,
4860  groupLinkIndex /*groupLinkIndex*/);
4861  }
4862  }
4863  else
4864  {
4865  __SS__ << "Illegal recursive parameters!" << __E__;
4866  __SS_THROW__;
4867  }
4868  __GEN_COUT__ << "recursiveInitFromFhiclPSet() "
4869  << "Done adding table '" << tableName << "' record(s)..." << __E__;
4870  if(TTEST(1))
4871  {
4872  std::stringstream ss;
4873  view->print(ss);
4874  __GEN_COUTT__ << "view->print()" << ss.str() << __E__;
4875  }
4876  }
4877 
4878 } // end recursiveInitFromFhiclPSet()
4879 
4880 //==============================================================================
4885 {
4886  __GEN_COUTS__(11) << "Checking if owner '" << ownerContextUID_ << "/" << ownerAppUID_
4887  << "' is first App in Context:\n"
4888  << StringMacros::stackTrace() << __E__;
4889 
4890  if(ownerContextUID_ == "" || ownerAppUID_ == "")
4891  {
4892  __GEN_COUTTV__(!forceNotFirstInContext_);
4893  return !forceNotFirstInContext_; // default to 'yes' unless forced
4894  }
4895 
4896  __GEN_COUTVS__(10, ownerContextUID_);
4897  __GEN_COUTVS__(10, ownerAppUID_);
4898 
4899  try
4900  {
4901  auto contextChildren =
4902  getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME + "/" +
4903  ownerContextUID_ + "/LinkToApplicationTable")
4904  .getChildrenNames(false /* byPriority */, true /* onlyStatusTrue */);
4905 
4906  if(contextChildren.size() == 0) // no enabled apps, check if owner is app[0]
4907  {
4908  contextChildren =
4909  getNode(ConfigurationManager::XDAQ_CONTEXT_TABLE_NAME + "/" +
4910  ownerContextUID_ + "/LinkToApplicationTable")
4911  .getChildrenNames(false /* byPriority */, false /* onlyStatusTrue */);
4912  __GEN_COUTVS__(10, StringMacros::vectorToString(contextChildren));
4913  }
4914  else
4915  __GEN_COUTVS__(10, StringMacros::vectorToString(contextChildren));
4916 
4917  bool isFirstAppInContext =
4918  contextChildren.size() == 0 || contextChildren[0] == ownerAppUID_;
4919 
4920  __GEN_COUTVS__(10, isFirstAppInContext);
4921 
4922  return isFirstAppInContext;
4923  }
4924  catch(...)
4925  {
4926  __GEN_COUTS__(10) << "Exception caught looking for XDAQ Context '"
4927  << ownerContextUID_ << "' in tree, so defaulting to 'yes'."
4928  << __E__;
4929  return true; // default to 'yes' if XDAQ Context doesn't exist
4930  }
4931 } // end isOwnerFirstAppInContext()
4932 
4933 //==============================================================================
4937  const std::string& otherSubsystemUID,
4938  std::string* userDataPathPtr /* = nullptr */,
4939  std::string* hostnamePtr /* = nullptr */,
4940  std::string* usernamePtr /* = nullptr */,
4941  std::string* fullNamePtr /* = nullptr */)
4942 {
4943  __GEN_COUTTV__(otherSubsystemUID);
4944 
4945  ConfigurationTree node =
4946  getNode(ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE)
4947  .getNode(otherSubsystemUID);
4948  std::string userPath = node.getNode("SubsystemUserDataPath").getValue();
4949  if(fullNamePtr)
4950  *fullNamePtr = node.getNode("SubsystemFullName").getValue();
4951 
4952  auto splitPath = StringMacros::getVectorFromString(userPath, {':'});
4953  __GEN_COUTTV__(StringMacros::vectorToString(splitPath));
4954 
4955  if(!splitPath.size() || splitPath.size() > 2)
4956  {
4957  __GEN_SS__ << "Illegal user data path specified for subsystem '"
4958  << otherSubsystemUID << "': " << userPath << __E__;
4959  __SS_ONLY_THROW__;
4960  }
4961  std::string userDataPath = splitPath[splitPath.size() - 1];
4962 
4963  //since we are running exec, cleanse the filename path for alphanumeric,_,-,/ only
4964  for(unsigned int i = 0; i < userDataPath.length(); ++i)
4965  if(!((userDataPath[i] >= 'a' && userDataPath[i] <= 'z') ||
4966  (userDataPath[i] >= 'A' && userDataPath[i] <= 'Z') ||
4967  (userDataPath[i] >= '0' && userDataPath[i] <= '9') ||
4968  userDataPath[i] == '-' || userDataPath[i] == '_' || userDataPath[i] == '/'))
4969  {
4970  __GEN_SS__ << "Illegal user data path specified (no special characters "
4971  "allowed) for subsystem '"
4972  << otherSubsystemUID << "': " << userPath << __E__;
4973  __SS_ONLY_THROW__;
4974  } // end filename cleanse
4975 
4976  if(userDataPathPtr)
4977  *userDataPathPtr = userDataPath;
4978 
4979  std::string username, hostname;
4980  if(splitPath.size() == 2) //then need to scp the file
4981  {
4982  //since we are running exec, cleanse the username@host path for alphanumeric,_,-,/ only
4983  std::vector<std::string> userHostSplit =
4984  StringMacros::getVectorFromString(splitPath[0], {'@'});
4985  __GEN_COUTTV__(userHostSplit.size());
4986  if(userHostSplit.size() == 1)
4987  hostname = userHostSplit[0];
4988  else if(userHostSplit.size() == 2)
4989  {
4990  username = userHostSplit[0];
4991  hostname = userHostSplit[1];
4992  }
4993  else
4994  {
4995  __GEN_SS__ << "Illegal remote username/host specified for subsystem '"
4996  << otherSubsystemUID << "': " << userPath << __E__;
4997  __SS_ONLY_THROW__;
4998  }
4999 
5000  for(unsigned int i = 0; userHostSplit.size() == 2 && i < username.length(); ++i)
5001  if(!((username[i] >= 'a' && username[i] <= 'z') ||
5002  (username[i] >= 'A' && username[i] <= 'Z') ||
5003  (username[i] >= '0' && username[i] <= '9') || username[i] == '-' ||
5004  username[i] == '_'))
5005  {
5006  __GEN_SS__ << "Illegal remote username specified for subsystem '"
5007  << otherSubsystemUID << "': " << userPath << __E__;
5008  __SS_ONLY_THROW__;
5009  }
5010  unsigned int ii = 0; //track last . to prevent weird . usage
5011  for(unsigned int i = 0; i < hostname.length(); ++i)
5012  if(!((hostname[i] >= 'a' && hostname[i] <= 'z') ||
5013  (hostname[i] >= 'A' && hostname[i] <= 'Z') ||
5014  (hostname[i] >= '0' && hostname[i] <= '9') || hostname[i] == '-' ||
5015  hostname[i] == '_'))
5016  {
5017  if(hostname[i] == '.' && i > ii + 1)
5018  {
5019  //its ok to have this . so track position
5020  ii = i;
5021  }
5022  else //else not ok to have .. or other characters
5023  {
5024  __GEN_SS__ << "Illegal remote hostname '" << hostname
5025  << "' specified for subsystem '" << otherSubsystemUID
5026  << "': " << userPath << __E__;
5027  __SS_ONLY_THROW__;
5028  }
5029  }
5030  }
5031  else if(splitPath.size() == 1) //then can just directly access the file
5032  {
5033  __GEN_COUT__ << "Local user date path identified." << __E__;
5034  }
5035  else
5036  {
5037  __GEN_SS__ << "Illegal user data path specified for subsystem '"
5038  << otherSubsystemUID << "': " << userPath << __E__;
5039  __SS_ONLY_THROW__;
5040  }
5041 
5042  if(hostnamePtr)
5043  *hostnamePtr = hostname;
5044  if(usernamePtr)
5045  *usernamePtr = username;
5046 
5047 } // end getOtherSubsystemInstanceInfo()
5048 
5049 //==============================================================================
5050 std::map<std::string /*groupType*/, std::pair<std::string /*groupName*/, TableGroupKey>>
5051 ConfigurationManager::getOtherSubsystemActiveTableGroups(
5052  const std::string& otherSubsystemUID,
5053  std::string* userDataPathPtr /* = nullptr */,
5054  std::string* hostnamePtr /* = nullptr */,
5055  std::string* usernamePtr /* = nullptr */)
5056 {
5057  std::map<std::string /*groupType*/,
5058  std::pair<std::string /*groupName*/, TableGroupKey>>
5059  retMap;
5060 
5061  __GEN_COUTTV__(otherSubsystemUID);
5062 
5063  std::string userDataPath;
5064  std::string username, hostname;
5065 
5066  getOtherSubsystemInstanceInfo(otherSubsystemUID, &userDataPath, &hostname, &username);
5067 
5068  __GEN_COUTTV__(userDataPath);
5069  __GEN_COUTTV__(username);
5070  __GEN_COUTTV__(hostname);
5071 
5072  if(userDataPathPtr)
5073  *userDataPathPtr = userDataPath;
5074  if(hostnamePtr)
5075  *hostnamePtr = hostname;
5076  if(usernamePtr)
5077  *usernamePtr = username;
5078 
5079  //enforce filename ends correctly
5080  std::string filename = userDataPath + "/ServiceData/ActiveTableGroups.cfg";
5081 
5082  std::string cmdResult;
5083 
5084  if(hostname != "")
5085  {
5086  std::string tmpSubsystemFilename =
5087  ConfigurationManager::ACTIVE_GROUPS_FILENAME + "." + otherSubsystemUID;
5088  __GEN_COUTTV__(tmpSubsystemFilename);
5089  if(username != "") //has username
5090  {
5091  cmdResult = StringMacros::exec(
5092  ("rm " + tmpSubsystemFilename + " 2>/dev/null; scp " + username + "@" +
5093  hostname + ":" + filename + " " + tmpSubsystemFilename + " 2>&1; cat " +
5094  tmpSubsystemFilename + " 2>&1")
5095  .c_str());
5096  }
5097  else
5098  cmdResult = StringMacros::exec(
5099  ("rm " + tmpSubsystemFilename + " 2>/dev/null; scp " + hostname + ":" +
5100  filename + " " + tmpSubsystemFilename + " 2>&1; cat " +
5101  tmpSubsystemFilename + " 2>&1")
5102  .c_str());
5103  }
5104  else //then can just directly access the file
5105  {
5106  __GEN_COUT__ << "Local user date path identified." << __E__;
5107  cmdResult = StringMacros::exec(("cat " + filename + " 2>&1").c_str());
5108  }
5109 
5110  __GEN_COUTTV__(cmdResult);
5111  if(cmdResult.find("Permission denied") != std::string::npos)
5112  {
5113  __GEN_SS__
5114  << "\n\nPermission denied accessing user data path specified for subsystem '"
5115  << otherSubsystemUID << "': ";
5116  if(username != "")
5117  ss << username << "@";
5118  if(hostname != "")
5119  ss << hostname << ":";
5120  ss << userDataPath << __E__;
5121  __SS_ONLY_THROW__;
5122  }
5123  else if(cmdResult.find("No such file or directory") != std::string::npos)
5124  {
5125  __GEN_SS__ << "\n\nActive tables groups file not found at user data path "
5126  "specified for subsystem '"
5127  << otherSubsystemUID << "': ";
5128  if(username != "")
5129  ss << username << "@";
5130  if(hostname != "")
5131  ss << hostname << ":";
5132  ss << userDataPath << __E__;
5133  __SS_ONLY_THROW__;
5134  }
5135 
5136  auto subsystemActiveGroupMap = StringMacros::getVectorFromString(
5137  cmdResult, {'\n'} /* delimieter*/, {' ', '\t'} /* whitespace*/);
5138  __GEN_COUTTV__(StringMacros::vectorToString(subsystemActiveGroupMap));
5139  __GEN_COUTTV__(subsystemActiveGroupMap.size());
5140 
5141  std::string //groupComment, groupAuthor, groupCreationTime,
5142  groupType;
5143  for(unsigned int i = 0; i + 1 < subsystemActiveGroupMap.size(); i += 2)
5144  {
5145  if(subsystemActiveGroupMap[i] == "" || subsystemActiveGroupMap[i + 1] == "-1")
5146  continue;
5147 
5148  __GEN_COUTT__ << "Loading type of subsystem '" << otherSubsystemUID << "' group "
5149  << subsystemActiveGroupMap[i] << "("
5150  << subsystemActiveGroupMap[i + 1] << ")" << __E__;
5151 
5152  try
5153  {
5154  loadTableGroup(subsystemActiveGroupMap[i] /*groupName*/,
5155  TableGroupKey(subsystemActiveGroupMap[i + 1]),
5156  false /*doActivate*/,
5157  0 /*groupMembers*/,
5158  0 /*progressBar*/,
5159  0 /*accumulateErrors*/,
5160  0, // &groupComment,
5161  0, //&groupAuthor,
5162  0, //&groupCreationTime,
5163  true /*doNotLoadMember*/,
5164  &groupType);
5165  }
5166  catch(const std::runtime_error& e)
5167  {
5168  __GEN_COUTT__ << "Ignoring error loading subsystem '" << otherSubsystemUID
5169  << "' group " << subsystemActiveGroupMap[i] << "("
5170  << subsystemActiveGroupMap[i + 1] << "): " << __E__ << e.what()
5171  << __E__;
5172  groupType = ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
5173  }
5174  retMap[groupType] = std::make_pair(subsystemActiveGroupMap[i],
5175  TableGroupKey(subsystemActiveGroupMap[i + 1]));
5176  } //end load table group loop
5177 
5178  __GEN_COUTTV__(StringMacros::mapToString(retMap));
5179  return retMap;
5180 } //end getOtherSubsystemActiveTableGroups()
5181 
5182 //==============================================================================
5184 std::set<std::string /* configAlias */>
5185 ConfigurationManager::getOtherSubsystemConfigAliases(const std::string& otherSubsystemUID)
5186 {
5187  std::set<std::string> retSet;
5188 
5189  __GEN_COUTTV__(otherSubsystemUID);
5190 
5191  std::map<std::string /*groupType*/,
5192  std::pair<std::string /*groupName*/, TableGroupKey>>
5193  retMap = getOtherSubsystemActiveTableGroups(otherSubsystemUID);
5194 
5195  __GEN_COUTTV__(StringMacros::mapToString(retMap));
5196 
5197  //load backbone
5198  auto it = retMap.find(
5199  ConfigurationManager::convertGroupTypeToName(GroupType::BACKBONE_TYPE));
5200  if(it == retMap.end())
5201  {
5202  __GEN_SS__
5203  << "No active Backbone group found in the active groups of remote subsystem '"
5204  << otherSubsystemUID << "!'" << __E__;
5205  __GEN_SS_THROW__;
5206  }
5207  auto it2 = retMap.find(
5208  ConfigurationManager::convertGroupTypeToName(GroupType::CONTEXT_TYPE));
5209  if(it2 == retMap.end())
5210  {
5211  __GEN_SS__
5212  << "No active Context group found in the active groups of remote subsystem '"
5213  << otherSubsystemUID << "!'" << __E__;
5214  __GEN_SS_THROW__;
5215  }
5216 
5217  std::string accumulatedWarnings;
5218 
5219  // be careful to not activate! which calls init() and then generates output files to disk
5220  // and changes the system active group; instead only setActiveView
5221  loadTableGroup(it->second.first,
5222  it->second.second,
5223  false /*doActivate*/,
5224  0 /*groupMembers*/,
5225  0 /*progressBar*/,
5226  &accumulatedWarnings /*accumulateWarnings = 0*/
5227  );
5228  __GEN_COUTTV__(accumulatedWarnings);
5229 
5230  //get aliases (a la ConfigurationManager::getActiveGroupAliases:2888)
5231  std::vector<std::pair<std::string, ConfigurationTree>> entries =
5232  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getChildren();
5233 
5234  for(auto& entry : entries)
5235  {
5236  if(entry.first.find("Context") == std::string::npos &&
5237  entry.first.find("Iterat") == std::string::npos)
5238  retSet.emplace(entry.first);
5239  }
5240  __GEN_COUTTV__(StringMacros::setToString(retSet));
5241  return retSet;
5242 } //end getOtherSubsystemConfigAliases()
5243 
5244 //==============================================================================
5246 std::set<std::string /* configAlias */>
5248  const std::string& otherSubsystemUID, const std::string& otherSubsystemFsmName)
5249 {
5250  std::set<std::string> retSet;
5251 
5252  std::map<std::string /*groupType*/,
5253  std::pair<std::string /*groupName*/, TableGroupKey>>
5254  retMap = getOtherSubsystemActiveTableGroups(otherSubsystemUID);
5255 
5256  //load backbone
5257  auto it = retMap.find(
5258  ConfigurationManager::convertGroupTypeToName(GroupType::BACKBONE_TYPE));
5259  if(it == retMap.end())
5260  {
5261  __GEN_SS__
5262  << "No active Backbone group found in the active groups of remote subsystem '"
5263  << otherSubsystemUID << "!'" << __E__;
5264  __GEN_SS_THROW__;
5265  }
5266  auto it2 = retMap.find(
5267  ConfigurationManager::convertGroupTypeToName(GroupType::CONTEXT_TYPE));
5268  if(it2 == retMap.end())
5269  {
5270  __GEN_SS__
5271  << "No active Context group found in the active groups of remote subsystem '"
5272  << otherSubsystemUID << "!'" << __E__;
5273  __GEN_SS_THROW__;
5274  }
5275 
5276  std::string accumulatedWarnings;
5277 
5278  // be careful to not activate! which calls init() and then generates output files to disk
5279  // and changes the system active group; instead only setActiveView
5280  loadTableGroup(it->second.first,
5281  it->second.second,
5282  false /*doActivate*/,
5283  0 /*groupMembers*/,
5284  0 /*progressBar*/,
5285  &accumulatedWarnings /*accumulateWarnings = 0*/
5286  );
5287  loadTableGroup(it2->second.first,
5288  it2->second.second,
5289  false /*doActivate*/,
5290  0 /*groupMembers*/,
5291  0 /*progressBar*/,
5292  &accumulatedWarnings /*accumulateWarnings = 0*/
5293  );
5294  __GEN_COUTTV__(accumulatedWarnings);
5295 
5296  //get aliases (a la ConfigurationManager::getActiveGroupAliases:2888)
5297  std::vector<std::pair<std::string, ConfigurationTree>> entries =
5298  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getChildren();
5299 
5300  //apply filter (a la GatewaySupervisor::addFilteredConfigAliasesToXML:5357)
5301 
5302  std::string stateMachineAliasFilter = "*"; // default to all
5303  try // if cant find alias, default to all
5304  {
5305  ConfigurationTree otherGatewayNode = getGatewaySupervisorNode();
5306  ConfigurationTree fsmFilterNode =
5307  otherGatewayNode.getNode("LinkToStateMachineTable")
5308  .getNode(otherSubsystemFsmName + "/SystemAliasFilter");
5309  if(!fsmFilterNode.isDefaultValue())
5310  stateMachineAliasFilter = fsmFilterNode.getValue<std::string>();
5311  else
5312  __GEN_COUT_INFO__ << "FSM has no SystemAliasFilter value." << __E__;
5313  }
5314  catch(std::runtime_error& e)
5315  {
5316  __COUT__ << "Ignoring unsetup SystemAliasFilter value: " << e.what() << __E__;
5317  }
5318  catch(...)
5319  {
5320  __COUT__ << "Ignoring unsetup SystemAliasFilter value." << __E__;
5321  }
5322 
5323  __COUT__ << "Applying alias filter for other user_data path FSM '"
5324  << otherSubsystemFsmName
5325  << "' and stateMachineAliasFilter = " << stateMachineAliasFilter << __E__;
5326 
5327  // filter list of aliases based on stateMachineAliasFilter
5328  // ! as first character means choose those that do NOT match filter
5329  // * can be used as wild card.
5330  {
5331  bool invertFilter =
5332  stateMachineAliasFilter.size() && stateMachineAliasFilter[0] == '!';
5333  std::vector<std::string> filterArr;
5334 
5335  size_t i = 0;
5336  if(invertFilter)
5337  ++i;
5338  size_t f;
5339  std::string tmp;
5340  while((f = stateMachineAliasFilter.find('*', i)) != std::string::npos)
5341  {
5342  tmp = stateMachineAliasFilter.substr(i, f - i);
5343  i = f + 1;
5344  filterArr.push_back(tmp);
5345  __COUTS__(20) << filterArr[filterArr.size() - 1] << " " << i << " of "
5346  << stateMachineAliasFilter.size() << __E__;
5347  }
5348  if(i <= stateMachineAliasFilter.size())
5349  {
5350  tmp = stateMachineAliasFilter.substr(i);
5351  filterArr.push_back(tmp);
5352  __COUTS__(20) << filterArr[filterArr.size() - 1] << " last." << __E__;
5353  }
5354 
5355  bool filterMatch;
5356 
5357  for(auto& aliasMapPair : entries)
5358  {
5359  __COUTS__(20) << "aliasMapPair.first: " << aliasMapPair.first << __E__;
5360 
5361  filterMatch = true;
5362 
5363  if(filterArr.size() == 1)
5364  {
5365  if(filterArr[0] != "" && filterArr[0] != "*" &&
5366  aliasMapPair.first != filterArr[0])
5367  filterMatch = false;
5368  }
5369  else
5370  {
5371  i = -1;
5372  for(f = 0; f < filterArr.size(); ++f)
5373  {
5374  if(!filterArr[f].size())
5375  continue; // skip empty filters
5376 
5377  if(f == 0) // must start with this filter
5378  {
5379  if((i = aliasMapPair.first.find(filterArr[f])) != 0)
5380  {
5381  filterMatch = false;
5382  break;
5383  }
5384  }
5385  else if(f == filterArr.size() - 1) // must end with this filter
5386  {
5387  if(aliasMapPair.first.rfind(filterArr[f]) !=
5388  aliasMapPair.first.size() - filterArr[f].size())
5389  {
5390  filterMatch = false;
5391  break;
5392  }
5393  }
5394  else if((i = aliasMapPair.first.find(filterArr[f])) ==
5395  std::string::npos)
5396  {
5397  filterMatch = false;
5398  break;
5399  }
5400  }
5401  }
5402 
5403  if(invertFilter)
5404  filterMatch = !filterMatch;
5405 
5406  __COUTS__(20) << "filterMatch=" << filterMatch << __E__;
5407 
5408  if(!filterMatch)
5409  continue;
5410 
5411  retSet.emplace(aliasMapPair.first);
5412 
5413  //If need more alias details, see ConfigurationGUISupervisor::handleGroupAliasesXML
5414  }
5415  }
5416 
5417  return retSet;
5418 } //end getOtherSubsystemFilteredConfigAliases()
5419 
5420 //==============================================================================
5423  const std::string& otherSubsystemUID,
5424  const std::string& configAlias,
5425  std::pair<std::string, TableGroupKey>& groupTranslation,
5426  std::string& groupComment,
5427  std::string& groupAuthor,
5428  std::string& groupCreationTime)
5429 {
5430  __GEN_COUTV__(otherSubsystemUID);
5431 
5432  std::map<std::string /*groupType*/,
5433  std::pair<std::string /*groupName*/, TableGroupKey>>
5434  retMap = getOtherSubsystemActiveTableGroups(otherSubsystemUID);
5435 
5436  //load backbone
5437  auto it = retMap.find(
5438  ConfigurationManager::convertGroupTypeToName(GroupType::BACKBONE_TYPE));
5439  if(it == retMap.end())
5440  {
5441  __GEN_SS__
5442  << "No active Backbone group found in the active groups of remote subsystem '"
5443  << otherSubsystemUID << "!'" << __E__;
5444  __GEN_SS_THROW__;
5445  }
5446  auto it2 = retMap.find(
5447  ConfigurationManager::convertGroupTypeToName(GroupType::CONTEXT_TYPE));
5448  if(it2 == retMap.end())
5449  {
5450  __GEN_SS__
5451  << "No active Context group found in the active groups of remote subsystem '"
5452  << otherSubsystemUID << "!'" << __E__;
5453  __GEN_SS_THROW__;
5454  }
5455 
5456  std::string accumulatedWarnings;
5457 
5458  // be careful to not activate! which calls init() and then generates output files to disk
5459  // and changes the system active group; instead only setActiveView
5460  loadTableGroup(it->second.first,
5461  it->second.second,
5462  false /*doActivate*/,
5463  0 /*groupMembers*/,
5464  0 /*progressBar*/,
5465  &accumulatedWarnings /*accumulateWarnings = 0*/
5466  );
5467  __GEN_COUTTV__(accumulatedWarnings);
5468 
5469  // (a la ConfigurationManager::getTableGroupFromAlias)
5470  try
5471  {
5472  // find runType in Group Aliases table
5473  ConfigurationTree entry =
5474  getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getNode(configAlias);
5475 
5476  groupTranslation = std::pair<std::string, TableGroupKey>(
5477  entry.getNode("GroupName").getValueAsString(),
5478  TableGroupKey(entry.getNode("GroupKey").getValueAsString()));
5479  __COUT__ << "Found " << configAlias << " translates to " << groupTranslation.first
5480  << "(" << groupTranslation.second << ")" << __E__;
5481 
5482  //get comment, author, creationTime
5483  try
5484  {
5485  loadTableGroup(groupTranslation.first,
5486  groupTranslation.second,
5487  false /*doActivate*/,
5488  0 /*groupMembers*/,
5489  0 /*progressBar*/,
5490  &accumulatedWarnings,
5491  &groupComment,
5492  &groupAuthor,
5493  &groupCreationTime,
5494  true /*doNotLoadMembers*/);
5495  }
5496  catch(...)
5497  {
5498  __COUT_WARN__ << "Failed to load group metadata." << __E__;
5499  }
5500  __COUT__ << "Found " << configAlias << " author: " << groupAuthor
5501  << ", createTime: " << groupCreationTime << ", comment: " << groupComment
5502  << __E__;
5503  }
5504  catch(...)
5505  {
5506  __GEN_SS__ << "Did not find the Configuration Alias '" << configAlias
5507  << "' in the active Backbone group of remote subsystem '"
5508  << otherSubsystemUID << "!'" << __E__;
5509  __GEN_SS_THROW__;
5510  }
5511 
5512 } //end getOtherSubsystemConfigAliasInfo()
5513 
5514 //==============================================================================
5516 TableBase* ConfigurationManager::getDesktopIconTable(void)
5517 {
5518  if(nameToTableMap_.find(DESKTOP_ICON_TABLE_NAME) == nameToTableMap_.end())
5519  {
5520  __SS__ << "Desktop icon table not found!" << __E__;
5521  ss << StringMacros::stackTrace() << __E__;
5522  __SS_THROW__;
5523  }
5524 
5525  return nameToTableMap_.at(DESKTOP_ICON_TABLE_NAME);
5526 } // end dynamicDesktopIconChange()
5527 
5528 //==============================================================================
5529 void ConfigurationManager::saveGroupNameAndKey(
5530  const std::pair<std::string /*group name*/, TableGroupKey>& theGroup,
5531  const std::string& fileName,
5532  bool appendMode /* = false */,
5533  const std::string& associatedUser /* = "" */)
5534 {
5535  std::string fullPath =
5536  ConfigurationManager::LAST_TABLE_GROUP_SAVE_PATH + "/" + fileName;
5537  __COUTT__ << "Saving group " << theGroup.first << "(" << theGroup.second << ") to "
5538  << (appendMode ? "history " : "") << "file: " << fullPath << __E__;
5539 
5540  std::ofstream groupFile;
5541  if(appendMode)
5542  {
5543  //force size to MAX record count
5544  const size_t MAX_RECORDS = 200;
5545  auto records = loadGroupHistory(fullPath);
5546  while(records.size() >= MAX_RECORDS)
5547  records.erase(records.begin()); //remove oldest record
5548  //rewrite file
5549  groupFile.open(fullPath.c_str());
5550  for(const auto& record : records)
5551  {
5552  groupFile << record.at("groupName") << "\n"
5553  << record.at("groupKey") << "\n"
5554  << record.at("time") << " , " << record.at("user") << "\n";
5555  } //end rewrite records loop
5556  }
5557  else //if not append mode, just overwrite
5558  groupFile.open(fullPath.c_str());
5559  if(!groupFile.is_open())
5560  {
5561  __SS__ << "Error. Can't open file to save group activity: " << fullPath << __E__;
5562  __SS_THROW__;
5563  }
5564  std::stringstream outss;
5565  outss << theGroup.first << "\n" << theGroup.second << "\n";
5566  outss << time(0);
5567  if(associatedUser != "") //add user on same line as time if available
5568  outss << " , " << associatedUser;
5569  outss << "\n";
5570  groupFile << outss.str().c_str();
5571  groupFile.close();
5572 } // end saveGroupNameAndKey()
5573 
5574 //==============================================================================
5580 std::pair<std::string /*group name*/, TableGroupKey>
5581 ConfigurationManager::loadGroupNameAndKey(const std::string& fileName,
5582  std::string& returnedTimeString)
5583 {
5584  std::string fullPath =
5585  ConfigurationManager::LAST_TABLE_GROUP_SAVE_PATH + "/" + fileName;
5586 
5587  FILE* groupFile = fopen(fullPath.c_str(), "r");
5588  if(!groupFile)
5589  {
5590  __COUT__ << "Can't open file: " << fullPath
5591  << ". Returning empty groupName and key -1" << __E__;
5592 
5593  return std::pair<std::string /*group name*/, TableGroupKey>("", TableGroupKey());
5594  }
5595 
5596  char line[500]; // assuming no group names longer than 500 chars
5597  // name and then key
5598  std::pair<std::string /*group name*/, TableGroupKey> theGroup;
5599 
5600  fgets(line, 500, groupFile); // name
5601  if(strlen(line) && line[strlen(line) - 1] == '\n')
5602  line[strlen(line) - 1] = '\0'; // remove trailing newline
5603  theGroup.first = line;
5604 
5605  fgets(line, 500, groupFile); // key
5606  int key;
5607  sscanf(line, "%d", &key);
5608  theGroup.second = key;
5609 
5610  fgets(line, 500, groupFile); // time
5611  time_t timestamp;
5612  sscanf(line, "%ld", &timestamp); // type long int
5613  // struct tm tmstruct;
5614  // ::localtime_r(&timestamp, &tmstruct);
5615  // ::strftime(line, 30, "%c %Z", &tmstruct);
5616  returnedTimeString = StringMacros::getTimestampString(timestamp); // line;
5617  fclose(groupFile);
5618 
5619  __COUTS__(2) << "theGroup.first=" << theGroup.first
5620  << " theGroup.second=" << theGroup.second << __E__;
5621 
5622  return theGroup;
5623 } // end loadGroupNameAndKey()
5624 
5625 //==============================================================================
5627 std::vector<
5628  std::map<std::string /* group field key */, std::string /* group field value */>>
5629 ConfigurationManager::loadGroupHistory(const std::string& groupAction,
5630  const std::string& groupType,
5631  bool formatTime /* = false */)
5632 {
5633  __COUTTV__(groupAction);
5634  __COUTTV__(groupType);
5635 
5636  std::string fullPath = ConfigurationManager::LAST_TABLE_GROUP_SAVE_PATH + "/";
5637 
5638  if(groupAction == "Activated")
5639  {
5640  if(groupType == ConfigurationManager::GROUP_TYPE_NAME_BACKBONE)
5641  fullPath += ConfigurationManager::ACTIVATED_BACKBONES_FILE;
5642  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONTEXT)
5643  fullPath += ConfigurationManager::ACTIVATED_CONTEXTS_FILE;
5644  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONFIGURATION)
5645  fullPath += ConfigurationManager::ACTIVATED_CONFIGS_FILE;
5646  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_ITERATE)
5647  fullPath += ConfigurationManager::ACTIVATED_ITERATES_FILE;
5648  }
5649  else if(groupAction == "Attempted Configure")
5650  {
5651  if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONFIGURATION)
5652  fullPath += ConfigurationManager::ATTEMPTED_CONFIGURE_CONFIGS_FILE;
5653  else if(groupType == "Config Alias")
5654  fullPath += ConfigurationManager::ATTEMPTED_CONFIGURE_CONFIG_ALIASES_FILE;
5655  }
5656  else if(groupAction == "Configured")
5657  {
5658  if(groupType == ConfigurationManager::GROUP_TYPE_NAME_BACKBONE)
5659  fullPath += ConfigurationManager::CONFIGURED_BACKBONES_FILE;
5660  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONTEXT)
5661  fullPath += ConfigurationManager::CONFIGURED_CONTEXTS_FILE;
5662  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONFIGURATION)
5663  fullPath += ConfigurationManager::CONFIGURED_CONFIGS_FILE;
5664  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_ITERATE)
5665  fullPath += ConfigurationManager::CONFIGURED_ITERATES_FILE;
5666  else if(groupType == "Config Alias")
5667  fullPath += ConfigurationManager::CONFIGURED_CONFIG_ALIASES_FILE;
5668  }
5669  else if(groupAction == "Started")
5670  {
5671  if(groupType == ConfigurationManager::GROUP_TYPE_NAME_BACKBONE)
5672  fullPath += ConfigurationManager::STARTED_BACKBONES_FILE;
5673  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONTEXT)
5674  fullPath += ConfigurationManager::STARTED_CONTEXTS_FILE;
5675  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONFIGURATION)
5676  fullPath += ConfigurationManager::STARTED_CONFIGS_FILE;
5677  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_ITERATE)
5678  fullPath += ConfigurationManager::STARTED_ITERATES_FILE;
5679  else if(groupType == "Config Alias")
5680  fullPath += ConfigurationManager::STARTED_CONFIG_ALIASES_FILE;
5681  }
5682  else if(groupAction == "Configured or Started")
5683  {
5684  if(groupType == ConfigurationManager::GROUP_TYPE_NAME_BACKBONE)
5685  fullPath += ConfigurationManager::CONFIGURED_OR_STARTED_BACKBONES_FILE;
5686  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONTEXT)
5687  fullPath += ConfigurationManager::CONFIGURED_OR_STARTED_CONTEXTS_FILE;
5688  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_CONFIGURATION)
5689  fullPath += ConfigurationManager::CONFIGURED_OR_STARTED_CONFIGS_FILE;
5690  else if(groupType == ConfigurationManager::GROUP_TYPE_NAME_ITERATE)
5691  fullPath += ConfigurationManager::CONFIGURED_OR_STARTED_ITERATES_FILE;
5692  else if(groupType == "Config Alias")
5693  fullPath += ConfigurationManager::CONFIGURED_OR_STARTED_CONFIG_ALIASES_FILE;
5694  }
5695 
5696  if(fullPath == ConfigurationManager::LAST_TABLE_GROUP_SAVE_PATH + "/")
5697  {
5698  __SS__ << "Illegal attempted group history request combination of groupAction: "
5699  << groupAction << ", and groupType: " << groupType << __E__;
5700  __SS_THROW__;
5701  }
5702  return loadGroupHistory(fullPath, formatTime);
5703 } // end loadGroupHistory()
5704 
5705 //==============================================================================
5707 std::vector<
5708  std::map<std::string /* group field key */, std::string /* group field value */>>
5709 ConfigurationManager::loadGroupHistory(const std::string& fullPath,
5710  bool formatTime /* = false */)
5711 {
5712  std::vector<
5713  std::map<std::string /* group field key */, std::string /* group field value */>>
5714  retVec;
5715 
5716  __COUTTV__(fullPath);
5717  FILE* groupFile = fopen(fullPath.c_str(), "r");
5718  if(!groupFile)
5719  {
5720  __COUT_WARN__ << "Can't open group history file (assuming no history yet): "
5721  << fullPath << __E__;
5722 
5723  __COUTTV__(retVec.size());
5724  return retVec;
5725  }
5726 
5727  char line[500]; // assuming no group names longer than 500 chars
5728  // name and then key
5729  std::pair<std::string /*group name*/, TableGroupKey> theGroup;
5730  std::string returnedTimeString, associatedUser;
5731  char user[500];
5732 
5733  while(fgets(line, 500, groupFile)) // name
5734  {
5735  if(strlen(line) && line[strlen(line) - 1] == '\n')
5736  line[strlen(line) - 1] = '\0'; // remove trailing newline
5737  theGroup.first = line;
5738 
5739  fgets(line, 500, groupFile); // key
5740  int key;
5741  sscanf(line, "%d", &key);
5742  theGroup.second = key;
5743 
5744  fgets(line, 500, groupFile); // time
5745  time_t timestamp;
5746  user[0] = '\0'; //clear in case not present in line
5747  sscanf(line, "%ld , %s", &timestamp, user); // type long int
5748  // struct tm tmstruct;
5749  // ::localtime_r(&timestamp, &tmstruct);
5750  // ::strftime(line, 30, "%c %Z", &tmstruct);
5751 
5752  __COUTS__(20) << "Read group from history file: " << theGroup.first << "("
5753  << theGroup.second << "), timestamp=" << timestamp
5754  << ", user=" << user << __E__;
5755 
5756  retVec.push_back({{"groupName", theGroup.first},
5757  {"groupKey", theGroup.second.toString()},
5758  {"time",
5759  formatTime ? StringMacros::getTimestampString(timestamp)
5760  : std::to_string(timestamp)},
5761  {"user", user}});
5762  } //end traversing group history file
5763 
5764  fclose(groupFile);
5765 
5766  __COUTTV__(retVec.size());
5767 
5768  return retVec;
5769 } // end loadGroupHistory()
5770 
5771 //==============================================================================
5774 try
5775 {
5776  __COUTT__ << "Initializing prerequisites for artdaq!" << __E__;
5777 
5778  auto activeTables = getActiveVersions();
5779  for(auto& tablePair : activeTables)
5780  {
5781  __COUTVS__(2, tablePair.first);
5782  try
5783  {
5784  nameToTableMap_.at(tablePair.first)->initPrereqsForARTDAQ(this);
5785  }
5786  catch(const std::runtime_error& e)
5787  {
5788  __COUTVS__(2, e.what());
5789  if(std::string(e.what()).find(
5790  "initPrereqsForARTDAQ() is not implemented for this table") ==
5791  std::string::npos)
5792  throw;
5793  //else ignore undefined virtual function error
5794  }
5795  } //end table loop
5796 
5797  __COUTT__ << "Done initializing prerequisites for artdaq!" << __E__;
5798 } // end initPrereqsForARTDAQ()
5799 catch(...)
5800 {
5801  __SS__ << "Error caught while initializing prerequisites for artdaq!";
5802  try
5803  {
5804  throw;
5805  }
5806  catch(const std::runtime_error& e)
5807  {
5808  ss << " Here was the error: " << e.what() << __E__;
5809  }
5810  __SS_THROW__;
5811 } // end initPrereqsForARTDAQ()
virtual std::map< std::string, TableVersion > getTableGroupMembers(std::string const &, bool=false) const
returns the set of table groups that contain the specified table name and version
std::map< std::string, std::map< std::string, TableVersion > > getVersionAliases(void) const
static const std::string & convertGroupTypeToName(const ConfigurationManager::GroupType &groupTypeId)
void restoreActiveTableGroups(bool throwErrors=false, const std::string &pathToActiveGroupsFile="", ConfigurationManager::LoadGroupType onlyLoadIfBackboneOrContext=ConfigurationManager::LoadGroupType::ALL_TYPES, std::string *accumulatedWarnings=0)
std::map< std::string, std::pair< std::string, TableGroupKey > > getActiveTableGroups(void) const
std::set< std::string > getOtherSubsystemConfigAliases(const std::string &otherSubsystemUID)
Ignore any System Aliases with "Context" or "Iterat" in the name.
void dumpActiveConfiguration(const std::string &filePath, const std::string &dumpType, const std::string &configurationAlias, const std::string &subsystemCommonList, const std::string &subsystemCommonOverrideList, const std::string &logEntry, const std::string &activeUsers, const std::string &activeStateMachine, std::ostream &altOut=std::cout)
void loadMemberMap(const std::map< std::string, TableVersion > &memberMap, std::string *accumulateWarnings=0)
std::map< std::string, TableVersion > getActiveVersions(void) const
getActiveVersions
std::shared_ptr< TableGroupKey > makeTheTableGroupKey(TableGroupKey key)
Setters/Modifiers.
void copyTableGroupFromCache(const ConfigurationManager &cacheConfigMgr, const std::map< std::string, TableVersion > &groupMembers, const std::string &configGroupName="", const TableGroupKey &tableGroupKey=TableGroupKey(TableGroupKey::INVALID), bool doActivate=false, bool ignoreVersionTracking=false)
void getOtherSubsystemInstanceInfo(const std::string &otherSubsystemUID, std::string *userDataPathPtr=nullptr, std::string *hostnamePtr=nullptr, std::string *usernamePtr=nullptr, std::string *fullNamePtr=nullptr)
ConfigurationManager(bool initForWriteAccess=false, bool initializeFromFhicl=false, bool forceNotFirstInContext=false)
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
void loadTableGroup(const std::string &tableGroupName, const TableGroupKey &tableGroupKey, bool doActivate=false, std::map< std::string, TableVersion > *groupMembers=0, ProgressBar *progressBar=0, std::string *accumulateWarnings=0, std::string *groupComment=0, std::string *groupAuthor=0, std::string *groupCreateTime=0, bool doNotLoadMember=false, std::string *groupTypeString=0, std::map< std::string, std::string > *groupAliases=0, ConfigurationManager::LoadGroupType groupTypeToLoad=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false, std::map< std::string, TableVersion > mergeInTables={}, std::map< std::string, TableVersion > overrideTables={})
TableBase * getVersionedTableByName(const std::string &tableName, TableVersion version, bool looseColumnMatching=false, std::string *accumulatedErrors=0, bool getRawData=false, bool touchLastAccessTime=true)
void init(std::string *accumulatedErrors=0, bool initForWriteAccess=false, std::string *accumulatedWarnings=0)
std::string getFirstPathToNode(const ConfigurationTree &node, const std::string &startPath="/") const
getFirstPathToNode
static ConfigurationManager::GroupType getTypeOfGroup(const std::map< std::string, TableVersion > &memberMap)
static const std::string & getTypeNameOfGroup(const std::map< std::string, TableVersion > &memberMap)
void destroyTableGroup(const std::string &theGroup="", bool onlyDeactivate=false)
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, TableVersion > *memberMap=0, std::string *accumulatedTreeErrors=0) const
std::map< std::string, ConfigurationTree > getChildrenMap(std::map< std::string, TableVersion > *memberMap=0, std::string *accumulatedTreeErrors=0) const
std::pair< std::string, TableGroupKey > getTableGroupFromAlias(std::string systemAlias, ProgressBar *progressBar=0)
Getters.
void applyContextCommonTables(const std::map< std::string, TableVersion > &mergeInTables, const std::map< std::string, TableVersion > &overrideTables)
static std::vector< std::map< std::string, std::string > > loadGroupHistory(const std::string &groupAction, const std::string &groupType, bool formatTime=false)
loadGroupHistory static
void getOtherSubsystemConfigAliasInfo(const std::string &otherSubsystemUID, const std::string &configAlias, std::pair< std::string, TableGroupKey > &groupTranslation, std::string &groupComment, std::string &groupAuthor, std::string &groupCreationTime)
returns configAlias translation group info by reference
ConfigurationTree getGatewaySupervisorNode(void) const
There can only be one active Gateway Superivsor app, so find it.
static const std::string ACTIVE_GROUPS_FILENAME
added env check for otsdaq_flatten_active_to_version to function
std::set< std::string > getOtherSubsystemFilteredConfigAliases(const std::string &otherSubsystemUID, const std::string &otherSubsystemFsmName)
Ignore any System Aliases with "Context" or "Iterat" in the name.
TableGroupKey loadConfigurationBackbone(void)
const TableBase * getTableByName(const std::string &configurationName) const
static const std::string READONLY_USER
Static members.
static std::pair< std::string, TableGroupKey > loadGroupNameAndKey(const std::string &fileName, std::string &returnedTimeString)
std::map< std::string, std::pair< std::string, TableGroupKey > > getActiveGroupAliases(void)
void initPrereqsForARTDAQ(void)
loadGroupHistory
bool isDisconnected(void) const
std::vector< std::string > getChildrenNames(bool byPriority=false, bool onlyStatusTrue=false) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
std::map< std::string, ConfigurationTree > getChildrenMap(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool onlyStatusTrue=false) const
const std::string & getValueAsString(bool returnLinkTableValue=false) const
void getValue(T &value) const
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
const std::string & getFieldName(void) const
alias for getValueName
bool isGroupLinkNode(void) const
bool isDefaultValue(void) const
boolean info
void step()
thread safe
Definition: ProgressBar.cc:74
const std::string & getTableName(void) const
Getters.
Definition: TableBase.cc:814
void setupMockupView(TableVersion version)
Definition: TableBase.cc:292
bool isActive(void)
isActive
Definition: TableBase.cc:950
const TableVersion & getViewVersion(void) const
always the active one
Definition: TableBase.cc:823
void print(std::ostream &out=std::cout) const
always prints active view
Definition: TableBase.cc:277
static std::string getFullGroupString(const std::string &groupName, const TableGroupKey &key, const std::string &preKey="_v", const std::string &postKey="")
bool isTemporaryVersion(void) const
std::string getChildLinkIndex(void) const
getChildLinkIndex
void setValueAsString(const std::string &value, unsigned int row, unsigned int col)
Definition: TableView.cc:1090
void deleteRow(int r)
Definition: TableView.cc:3575
unsigned int getColStatus(void) const
Definition: TableView.cc:1407
unsigned int getLinkGroupIDColumn(const std::string &childLinkIndex) const
Definition: TableView.cc:1858
bool getChildLink(const unsigned int &col, bool &isGroup, std::pair< unsigned int, unsigned int > &linkPair) const
Definition: TableView.cc:3605
void init(void)
Definition: TableView.cc:196
std::string getValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const
Definition: TableView.cc:973
int fillFromJSON(const std::string &json)
Definition: TableView.cc:2374
unsigned int getColUID(void) const
Definition: TableView.cc:1322
void setValue(const T &value, unsigned int row, unsigned int col)
< in included .icc source
unsigned int addRow(const std::string &author="", unsigned char incrementUniqueData=false, const std::string &baseNameAutoUID="", unsigned int rowToAdd=(unsigned int) -1, std::string childLinkIndex="", std::string groupId="")
Definition: TableView.cc:3490
defines used also by OtsConfigurationWizardSupervisor
static std::string getTimestampString(const std::string &linuxTimeInSeconds)
static void getVectorFromString(const std::string &inputString, std::vector< std::string > &listToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'}, std::vector< char > *listOfDelimiters=0, bool decodeURIComponents=false)
static std::string exec(const char *cmd)
static std::string setToString(const std::set< T > &setToReturn, const std::string &delimeter=", ")
setToString ~
static std::string vectorToString(const std::vector< T > &setToReturn, const std::string &delimeter=", ")
vectorToString ~
static std::string escapeJSONStringEntities(const std::string &str)
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")
static void getMapFromString(const std::string &inputString, std::map< S, T > &mapToReturn, const std::set< char > &pairPairDelimiter={',', '|', '&'}, const std::set< char > &nameValueDelimiter={'=', ':'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'})
getMapFromString ~
static std::string stackTrace(void)