otsdaq  3.04.02
AllSupervisorInfo.cc
1 #include "otsdaq/SupervisorInfo/AllSupervisorInfo.h"
2 
3 #include "otsdaq/Macros/CoutMacros.h"
4 #include "otsdaq/MessageFacility/MessageFacility.h"
5 
6 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
7 #include "otsdaq/TablePlugins/XDAQContextTable/XDAQContextTable.h"
8 
9 #include <iostream>
10 
11 using namespace ots;
12 
13 const bool AllSupervisorInfo::MACROMAKER_MODE =
14  ((getenv("MACROMAKER_MODE") ==
15  NULL) // check Macro Maker mode environment variable in a safe way
16  ? (false)
17  : ((std::string(__ENV__("MACROMAKER_MODE")) == "1") ? true : false));
18 
19 //==============================================================================
20 AllSupervisorInfo::AllSupervisorInfo(void)
21  : theSupervisorInfo_(nullptr)
22  , theWizardInfo_(nullptr)
23  , theARTDAQSupervisorInfo_(nullptr)
24 {
25 }
26 
27 //==============================================================================
28 AllSupervisorInfo::AllSupervisorInfo(xdaq::ApplicationContext* applicationContext)
30 {
31  init(applicationContext);
32 }
33 
34 //==============================================================================
35 AllSupervisorInfo::~AllSupervisorInfo(void) { destroy(); }
36 
37 //==============================================================================
38 void AllSupervisorInfo::destroy(void)
39 {
40  allSupervisorInfo_.clear();
41  allFETypeSupervisorInfo_.clear();
42  allDMTypeSupervisorInfo_.clear();
43 
44  theSupervisorInfo_ = nullptr;
45  theWizardInfo_ = nullptr;
46  theARTDAQSupervisorInfo_ = nullptr;
47 
48  SupervisorDescriptorInfoBase::destroy();
49 
50 } // end destroy()
51 
52 //==============================================================================
53 void AllSupervisorInfo::init(xdaq::ApplicationContext* applicationContext)
54 {
55  __COUT__ << "Initializing info based on XDAQ context..." << __E__;
56 
57  AllSupervisorInfo::destroy();
58  SupervisorDescriptorInfoBase::init(applicationContext);
59 
60  auto allDescriptors = SupervisorDescriptorInfoBase::getAllDescriptors();
61  // ready.. loop through all descriptors, and organize
62 
63  // for(const auto& descriptor:allDescriptors)
64  // {
65  // SupervisorInfo tempSupervisorInfo(
66  // descriptor.second /* descriptor */,
67  // "" /* config app name */,"" /* config parent context name */
69  // );
70  //
71  // __COUT__ << "id " << descriptor.second->getLocalId() << " url " <<
72  // descriptor.second->getContextDescriptor()->getURL() << __E__;
73  //
74  // }
75  // __COUTV__(XDAQContextTable::GATEWAY_SUPERVISOR_CLASS);
76 
77  // Steps:
78  // 1. first pass, identify Wiz mode or not
79  // 2. second pass, organize supervisors
80 
81  bool isWizardMode = false;
82  theSupervisorInfo_ = nullptr; // reset
83  theWizardInfo_ = nullptr; // reset
84  theARTDAQSupervisorInfo_ = nullptr; // reset
85 
86  // first pass, identify Wiz mode or not
87  // accept first encountered (wizard or gateway) as the mode
88  for(const auto& descriptor : allDescriptors)
89  {
90  SupervisorInfo tempSupervisorInfo(
91  descriptor.second /* descriptor */,
92  "" /* config app name */,
93  "" /* config parent context name */ // skip configuration info
94  );
95 
96  // check for gateway supervisor
97  if(tempSupervisorInfo.isGatewaySupervisor())
98  {
99  // found normal mode, done with first pass
100  isWizardMode = false;
101  break;
102  }
103  else if(tempSupervisorInfo.isWizardSupervisor())
104  {
105  // found wiz mode, done with first pass
106  isWizardMode = true;
107  break;
108  }
109  }
110 
111  if(AllSupervisorInfo::MACROMAKER_MODE)
112  __COUT__ << "Initializing info for Macro Maker mode XDAQ context..." << __E__;
113  else if(isWizardMode)
114  __COUT__ << "Initializing info for Wiz mode XDAQ context..." << __E__;
115  else
116  __COUT__ << "Initializing info for Normal mode XDAQ context..." << __E__;
117  std::unique_ptr<ConfigurationManager> cfgMgr(
118  (isWizardMode || AllSupervisorInfo::MACROMAKER_MODE)
119  ? 0
120  : new ConfigurationManager(false /* initForWriteAccess */,
121  false /* doInitializeFromFhicl */,
122  true /* forceNotFirstInContext */));
123  const XDAQContextTable* contextConfig =
124  (isWizardMode || AllSupervisorInfo::MACROMAKER_MODE)
125  ? nullptr
126  : cfgMgr->__GET_CONFIG__(XDAQContextTable);
127  //__COUTV__(contextConfig);
128 
129  // For TRACE controllers in normal mode, temporarily make a map by hostname of supervisors
130  // std::map<std::string /*hostname*/,std::pair<unsigned int, SupervisorInfo>> TRACEAppMap;
131 
132  std::string name, contextName;
133  // do not involve the Configuration Manager
134  // as it adds no valid information to the supervisors
135  // present in wiz mode
136  for(const auto& descriptor : allDescriptors)
137  {
138  name = contextConfig ? contextConfig->getApplicationUID(
139  descriptor.second->getContextDescriptor()->getURL(),
140  descriptor.second->getLocalId())
141  : "" /* config app name */;
142  contextName = contextConfig
143  ? contextConfig->getContextUID(
144  descriptor.second->getContextDescriptor()->getURL())
145  : "" /* config parent context name */;
146 
147  auto /*<iterator,bool>*/ emplacePair =
148  allSupervisorInfo_.emplace(std::pair<unsigned int, SupervisorInfo>(
149  descriptor.second->getLocalId(), // descriptor.first,
150  SupervisorInfo(descriptor.second /* descriptor */, name, contextName)));
151  if(!emplacePair.second)
152  {
153  __SS__ << "Error! Duplicate Application IDs are not allowed. ID ="
154  << descriptor.second->getLocalId() << __E__;
155  __SS_THROW__;
156  }
157 
158  //__COUTV__(emplacePair.first->second.getName());
159  //__COUTV__(emplacePair.first->second.getContextName());
160 
161  // emplace in allTraceControllerSupervisorInfo_ to find app per host to control trace
162  // NOTE: it will fail if there is already an entry for this hostname (which is what we want - keep one app per host)
163  if(emplacePair.first->second.isTypeARTDAQSupervisor())
164  {
165  // make sure artdaq Supervisor represents its host
166  if(theARTDAQSupervisorInfo_)
167  {
168  __SS__ << "Error! Multiple ARTDAQ Supervisors of class "
169  << XDAQContextTable::ARTDAQ_SUPERVISOR_CLASS
170  << " found. There can only be one. ID ="
171  << descriptor.second->getLocalId() << __E__;
172  __SS_THROW__;
173  }
174 
175  theARTDAQSupervisorInfo_ = &(emplacePair.first->second);
176  }
177 
179  // now organize new descriptor by class...
180 
181  // check for gateway supervisor
182  // note: necessarily exclusive to other Supervisor types
183  if(emplacePair.first->second.isGatewaySupervisor())
184  {
185  if(theSupervisorInfo_)
186  {
187  __SS__ << "Error! Multiple Gateway Supervisors of class "
188  << XDAQContextTable::GATEWAY_SUPERVISOR_CLASS
189  << " found. There can only be one. ID ="
190  << descriptor.second->getLocalId() << __E__;
191  __SS_THROW__;
192  }
193  theSupervisorInfo_ = &(emplacePair.first->second);
194  continue;
195  }
196 
197  // check for wizard supervisor
198  // note: necessarily exclusive to other Supervisor types
199  if(emplacePair.first->second.isWizardSupervisor())
200  {
201  if(theWizardInfo_)
202  {
203  __SS__ << "Error! Multiple Wizard Supervisors of class "
204  << XDAQContextTable::WIZARD_SUPERVISOR_CLASS
205  << " found. There can only be one. ID ="
206  << descriptor.second->getLocalId() << __E__;
207  __SS_THROW__;
208  }
209  theWizardInfo_ = &(emplacePair.first->second);
210 
211  continue;
212  }
213 
214  // check for FE type, then add to FE group
215  // note: not necessarily exclusive to other Supervisor types
216  if(emplacePair.first->second.isTypeFESupervisor())
217  {
218  allFETypeSupervisorInfo_.emplace(
219  std::pair<unsigned int, const SupervisorInfo&>(
220  emplacePair.first->second.getId(), emplacePair.first->second));
221  }
222 
223  // check for DM type, then add to DM group
224  // note: not necessarily exclusive to other Supervisor types
225  if(emplacePair.first->second.isTypeDMSupervisor())
226  {
227  allDMTypeSupervisorInfo_.emplace(
228  std::pair<unsigned int, const SupervisorInfo&>(
229  emplacePair.first->second.getId(), emplacePair.first->second));
230  }
231 
232  // check for Logbook type, then add to Logbook group
233  // note: not necessarily exclusive to other Supervisor types
234  if(emplacePair.first->second.isTypeLogbookSupervisor())
235  {
236  allLogbookTypeSupervisorInfo_.emplace(
237  std::pair<unsigned int, const SupervisorInfo&>(
238  emplacePair.first->second.getId(), emplacePair.first->second));
239  }
240 
241  // check for MacroMaker type, then add to MacroMaker group
242  // note: not necessarily exclusive to other Supervisor types
243  if(emplacePair.first->second.isTypeMacroMakerSupervisor())
244  {
245  allMacroMakerTypeSupervisorInfo_.emplace(
246  std::pair<unsigned int, const SupervisorInfo&>(
247  emplacePair.first->second.getId(), emplacePair.first->second));
248  }
249 
250  } // end main extraction loop
251 
252  if(AllSupervisorInfo::MACROMAKER_MODE)
253  {
254  if(theWizardInfo_ || theSupervisorInfo_)
255  {
256  __SS__ << "Error! For MacroMaker mode, must not have one "
257  << XDAQContextTable::GATEWAY_SUPERVISOR_CLASS << " OR one "
258  << XDAQContextTable::WIZARD_SUPERVISOR_CLASS
259  << " as part of the context configuration! "
260  << "One was found." << __E__;
261  __SS_THROW__;
262  }
263  if(allMacroMakerTypeSupervisorInfo_.size() != 1)
264  {
265  __SS__ << "Error! For MacroMaker mode, must have one and only one "
266  << *(XDAQContextTable::MacroMakerTypeClassNames_.begin())
267  << " as part of the context configuration! "
268  << allMacroMakerTypeSupervisorInfo_.size() << " were found." << __E__;
269  __SS_THROW__;
270  }
271  }
272  else if((!theWizardInfo_ && !theSupervisorInfo_) ||
273  (theWizardInfo_ && theSupervisorInfo_))
274  {
275  __SS__ << "Error! Must have one " << XDAQContextTable::GATEWAY_SUPERVISOR_CLASS
276  << " OR one " << XDAQContextTable::WIZARD_SUPERVISOR_CLASS
277  << " as part of the context configuration! "
278  << "Neither (or both) were found." << __E__;
279  __SS_THROW__;
280  }
281 
282  // wrap up TRACE controller map handling
283  {
284  // now create the list of TRACE Controller apps (one per host, but priority to artdaq supervisor)
285  allTraceControllerSupervisorInfo_.clear();
286 
287  if(theARTDAQSupervisorInfo_) // priority to artdaq supervisor
288  {
289  __COUT__ << "The ARTDAQ TRACE-controller app for hostname '"
290  << theARTDAQSupervisorInfo_->getHostname()
291  << "' is CLASS:LID = " << theARTDAQSupervisorInfo_->getClass() << ":"
292  << theARTDAQSupervisorInfo_->getId() << __E__;
293 
294  // DO NOT USE make_pair here.. it somehow infers types that break the map
295  allTraceControllerSupervisorInfo_.emplace(
296  std::pair<std::string, const SupervisorInfo&>(
297  theARTDAQSupervisorInfo_->getHostname(), *theARTDAQSupervisorInfo_));
298  }
299 
300  // the use emplace, because it will fail insert on collisions! (and we want to keep artdaq selection above)
301  for(auto& TRACEApp : allSupervisorInfo_)
302  {
303  // NOTE!! need to copy const SupervisorInfo& from the persistent copy in the allSupervisorInfo
304  if(allTraceControllerSupervisorInfo_
305  .emplace(std::pair<std::string, const SupervisorInfo&>(
306  TRACEApp.second.getHostname(),
307  allSupervisorInfo_.at(TRACEApp.first)))
308  .second)
309  {
310  __COUT__ << "The TRACE-controller app for hostname '"
311  << TRACEApp.second.getHostname()
312  << "' is CLASS:LID = " << TRACEApp.second.getClass() << ":"
313  << TRACEApp.second.getId()
314  << " name = " << TRACEApp.second.getName() << __E__;
315  }
316  // allTraceControllerSupervisorInfo_.emplace(
317  // std::pair<unsigned int, const SupervisorInfo&>(
318  // TRACEApp.second.second.getId(),
319  // allSupervisorInfo_.at(TRACEApp.second.second.getId())));
320  }
321  __COUT__ << "TRACE-controller app count = "
322  << allTraceControllerSupervisorInfo_.size() << __E__;
323 
324  // for(auto& TRACEApp : allTraceControllerSupervisorInfo_)
325  // {
326  // __COUT__ << "The TRACE-controller for hostname = " << TRACEApp.first << "/" << TRACEApp.second.getId() << " is ..."
327  // << " name = " << TRACEApp.second.getName() << " class = " << TRACEApp.second.getClass() << " hostname = " << TRACEApp.second.getHostname()
328  // << __E__;
329  // }
330  }
331 
332  SupervisorDescriptorInfoBase::destroy();
333 
334  __COUT__ << "Supervisor Info initialization complete!" << __E__;
335 
336  // for debugging
337  // getOrderedSupervisorDescriptors("Configure");
338 } // end init()
339 
340 //==============================================================================
341 const SupervisorInfo& AllSupervisorInfo::getSupervisorInfo(xdaq::Application* app) const
342 {
343  auto it = allSupervisorInfo_.find(app->getApplicationDescriptor()->getLocalId());
344  if(it == allSupervisorInfo_.end())
345  {
346  __SS__ << "Could not find: " << app->getApplicationDescriptor()->getLocalId()
347  << std::endl;
348  __SS_THROW__;
349  }
350  return it->second;
351 } //end getSupervisorInfo()
352 
353 //==============================================================================
355  xdaq::Application* app,
356  const std::string& status,
357  const unsigned int progress,
358  const std::string& detail,
359  std::vector<SupervisorInfo::SubappInfo> subapps,
360  const uint64_t availableLogSpaceKB,
361  const uint64_t availableDataSpaceKB)
362 {
363  setSupervisorStatus(app->getApplicationDescriptor()->getLocalId(),
364  status,
365  progress,
366  detail,
367  subapps,
368  availableLogSpaceKB,
369  availableDataSpaceKB);
370 } // end setSupervisorStatus()
371 //==============================================================================
373  const SupervisorInfo& appInfo,
374  const std::string& status,
375  const unsigned int progress,
376  const std::string& detail,
377  std::vector<SupervisorInfo::SubappInfo> subapps,
378  const uint64_t availableLogSpaceKB,
379  const uint64_t availableDataSpaceKB)
380 {
381  setSupervisorStatus(appInfo.getId(),
382  status,
383  progress,
384  detail,
385  subapps,
386  availableLogSpaceKB,
387  availableDataSpaceKB);
388 } // end setSupervisorStatus()
389 //==============================================================================
391  const unsigned int& id,
392  const std::string& status,
393  const unsigned int progress,
394  const std::string& detail,
395  std::vector<SupervisorInfo::SubappInfo> subapps,
396  const uint64_t availableLogSpaceKB,
397  const uint64_t availableDataSpaceKB)
398 {
399  auto it = allSupervisorInfo_.find(id);
400  if(it == allSupervisorInfo_.end())
401  {
402  __SS__ << "Could not find: " << id << __E__;
403  __SS_THROW__;
404  }
405  // non-blocking here, it's ok if the status is not updated (it is probably blocked on purpose, for exampled by the GatewaySupervisor broadcast threads)
406  if(allSupervisorInfoMutex_[id].try_lock())
407  {
408  if(progress > 100)
409  __COUT__ << "What happened 2? " << progress << __E__;
410  it->second.setStatus(
411  status, progress, detail, availableLogSpaceKB, availableDataSpaceKB);
412  //if subapps size mismatch, then clear to eliminate renamed subapps
413  if(it->second.getSubappInfo().size() != subapps.size())
414  it->second.clearSubapps();
415  for(auto& subapp : subapps)
416  {
417  it->second.copySubappStatus(subapp);
418  }
419  allSupervisorInfoMutex_[id].unlock();
420  }
421 } // end setSupervisorStatus()
422 
423 //==============================================================================
424 void AllSupervisorInfo::clearSupervisorSubappsStatus(const SupervisorInfo& appInfo)
425 {
426  auto it = allSupervisorInfo_.find(appInfo.getId());
427  if(it == allSupervisorInfo_.end())
428  {
429  __SS__ << "Could not find: " << appInfo.getId() << __E__;
430  __SS_THROW__;
431  }
432  // non-blocking here, it's ok if the status is not updated (it is probably blocked on purpose, for exampled by the GatewaySupervisor broadcast threads)
433  if(allSupervisorInfoMutex_[appInfo.getId()].try_lock())
434  {
435  it->second.clearSubapps();
436  allSupervisorInfoMutex_[appInfo.getId()].unlock();
437  }
438 } //end clearSupervisorSubappsStatus()
439 
440 //==============================================================================
441 const SupervisorInfo& AllSupervisorInfo::getGatewayInfo(void) const
442 {
443  if(!theSupervisorInfo_)
444  {
445  __SS__ << "AllSupervisorInfo was not initialized or no Application of type "
446  << XDAQContextTable::GATEWAY_SUPERVISOR_CLASS << " found!" << __E__
447  << StringMacros::stackTrace() << __E__;
448  __SS_THROW__;
449  }
450  return *theSupervisorInfo_;
451 }
452 //==============================================================================
453 XDAQ_CONST_CALL xdaq::ApplicationDescriptor* AllSupervisorInfo::getGatewayDescriptor(
454  void) const
455 {
456  return getGatewayInfo().getDescriptor();
457 }
458 
459 //==============================================================================
460 const SupervisorInfo& AllSupervisorInfo::getWizardInfo(void) const
461 {
462  if(!theWizardInfo_)
463  {
464  __SS__ << "AllSupervisorInfo was not initialized or no Application of type "
465  << XDAQContextTable::WIZARD_SUPERVISOR_CLASS << " found!" << __E__;
466  __SS_THROW__;
467  }
468  return *theWizardInfo_;
469 }
470 //==============================================================================
471 XDAQ_CONST_CALL xdaq::ApplicationDescriptor* AllSupervisorInfo::getWizardDescriptor(
472  void) const
473 {
474  return getWizardInfo().getDescriptor();
475 }
476 
477 //==============================================================================
478 const SupervisorInfo& AllSupervisorInfo::getArtdaqSupervisorInfo(void) const
479 {
480  if(!theARTDAQSupervisorInfo_)
481  {
482  __SS__ << "AllSupervisorInfo was not initialized or no Application of type "
483  << XDAQContextTable::ARTDAQ_SUPERVISOR_CLASS << " found!" << __E__;
484  __SS_THROW__;
485  }
486  return *theARTDAQSupervisorInfo_;
487 } // end getArtdaqSupervisorInfo()
488 
489 //==============================================================================
490 std::vector<std::vector<const SupervisorInfo*>>
491 AllSupervisorInfo::getOrderedSupervisorDescriptors(
492  const std::string& stateMachineCommand, bool onlyGatewayContextSupervisors) const
493 {
494  __COUT__ << "getOrderedSupervisorDescriptors for command " << stateMachineCommand
495  << __E__;
496 
497  std::map<uint64_t /*priority*/, std::vector<unsigned int /*appId*/>>
498  orderedByPriority;
499 
500  try
501  {
502  ConfigurationManager cfgMgr;
503  const std::vector<XDAQContextTable::XDAQContext>& contexts =
504  cfgMgr.__GET_CONFIG__(XDAQContextTable)->getContexts();
505 
506  for(const auto& context : contexts)
507  if(context.status_)
508  for(const auto& app : context.applications_)
509  {
510  if(!app.status_)
511  continue; // skip disabled apps
512 
513  auto it = app.stateMachineCommandPriority_.find(stateMachineCommand);
514  if(it == app.stateMachineCommandPriority_.end())
515  orderedByPriority
517  .push_back(app.id_); // if no priority, then default to
518  // XDAQContextTable::XDAQApplication::DEFAULT_PRIORITY
519  else // take value, and do not allow DEFAULT value of 0 -> force to
520  // XDAQContextTable::XDAQApplication::DEFAULT_PRIORITY
521  orderedByPriority[it->second ? it->second
524  .push_back(app.id_);
525 
526  //__COUT__ << "app.id_ " << app.id_ << __E__;
527  }
528  }
529  catch(...)
530  {
531  __COUT_ERR__ << "SupervisorDescriptorInfoBase could not access the XDAQ Context "
532  "and Application configuration through the Context Table "
533  "Group."
534  << __E__;
535  throw;
536  }
537 
538  __COUT__ << "Here is the order supervisors will be " << stateMachineCommand
539  << "'d:" << __E__;
540 
541  // return ordered set of supervisor infos
542  // skip over Gateway Supervisor,
543  // and other supervisors that do not need state transitions.
544  std::vector<std::vector<const SupervisorInfo*>> retVec;
545  bool createContainer;
546  const std::string whitespace = " ";
547  for(const auto& priorityAppVector : orderedByPriority)
548  {
549  createContainer = true;
550 
551  for(const auto& priorityApp : priorityAppVector.second)
552  {
553  auto it = allSupervisorInfo_.find(priorityApp);
554  if(it == allSupervisorInfo_.end())
555  {
556  __SS__
557  << "Error! Was AllSupervisorInfo properly initialized? The app.id_ "
558  << priorityApp << " priority "
559  << (unsigned int)priorityAppVector.first
560  << " could not be found in AllSupervisorInfo. Was the Context "
561  "changed? Rebooting ots may fix this issue."
562  << __E__;
563  __SS_THROW__;
564  }
565 
566  //__COUT__ << it->second.getName() << " [" << it->second.getId() << "]: " << "
567  // priority? " << (unsigned int)priorityAppVector.first <<
568  //__E__;
569 
570  if(onlyGatewayContextSupervisors &&
571  it->second.getContextName() != theSupervisorInfo_->getContextName())
572  continue; // for shutdown and startup only broadcast to apps that are local to the Gateway supervisor
573 
574  if(it->second.isGatewaySupervisor())
575  continue; // skip gateway supervisor
576  if(it->second.isTypeLogbookSupervisor())
577  continue; // skip logbook supervisor(s)
578  if(it->second.isTypeMacroMakerSupervisor())
579  continue; // skip macromaker supervisor(s)
580  if(it->second.isTypeConfigurationGUISupervisor())
581  continue; // skip configurationGUI supervisor(s)
582  if(it->second.isTypeChatSupervisor())
583  continue; // skip chat supervisor(s)
584  if(it->second.isTypeConsoleSupervisor())
585  continue; // skip console supervisor(s)
586  if(it->second.isTypeCodeEditorSupervisor())
587  continue; // skip code editor supervisor(s)
588 
589  if(createContainer) // create container first time
590  {
591  retVec.push_back(std::vector<const SupervisorInfo*>());
592 
593  // if default priority, create a new vector container for each entry
594  // so they happen in sequence by default
595  // if(priorityAppVector.first !=
596  // XDAQContextTable::XDAQApplication::DEFAULT_PRIORITY)
597  // createContainer = false;
598 
599  createContainer = false;
600  }
601  retVec[retVec.size() - 1].push_back(&(it->second));
602 
603  __COUT__ << "\t" << it->second.getName() << " [LID=" << it->second.getId()
604  << "]: "
605  << (it->second.getName().size() > whitespace.size()
606  ? ""
607  : whitespace.substr(
608  0, whitespace.size() - it->second.getName().size()))
609  << " priority " << (unsigned int)priorityAppVector.first << " count "
610  << retVec[retVec.size() - 1].size() << __E__;
611  }
612  } // end equal priority loop
613  return retVec;
614 } //end getOrderedSupervisorDescriptors()
bool isWizardMode(void) const
BOOLs.
void setSupervisorStatus(xdaq::Application *app, const std::string &status, const unsigned int progress=100, const std::string &detail="", std::vector< SupervisorInfo::SubappInfo > subapps={}, const uint64_t availableLogSpaceKB=0, const uint64_t availableDataSpaceKB=0)
SETTERs.
XDAQ_CONST_CALL xdaq::ApplicationDescriptor * getDescriptor(void) const
Getters ----------------—.
std::string getContextUID(const std::string &url) const
defines used also by OtsConfigurationWizardSupervisor
static std::string stackTrace(void)