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