otsdaq  v2_04_02
XDAQContextTable_table.cc
1 #include "otsdaq/ConfigurationInterface/ConfigurationManager.h"
2 #include "otsdaq/Macros/TablePluginMacros.h"
3 #include "otsdaq/TablePlugins/XDAQContextTable.h"
4 
5 #include <stdio.h>
6 #include <fstream> // std::fstream
7 #include <iostream>
8 
9 using namespace ots;
10 
11 // clang-format off
12 
13 #define XDAQ_RUN_FILE std::string(__ENV__("XDAQ_CONFIGURATION_DATA_PATH")) + "/" + std::string(__ENV__("XDAQ_CONFIGURATION_XML")) + ".xml"
14 #define APP_PRIORITY_FILE std::string(__ENV__("XDAQ_CONFIGURATION_DATA_PATH")) + "/" + "xdaqAppStateMachinePriority"
15 
16 const std::string XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS = "ots::Supervisor"; // still allowed for now, in StartOTS
17 const std::string XDAQContextTable::GATEWAY_SUPERVISOR_CLASS = "ots::GatewaySupervisor";
18 const std::string XDAQContextTable::WIZARD_SUPERVISOR_CLASS = "ots::WizardSupervisor";
19 const std::set<std::string> XDAQContextTable::FETypeClassNames_ = { "ots::FESupervisor", "ots::FEDataManagerSupervisor", "ots::ARTDAQFEDataManagerSupervisor"};
20 const std::set<std::string> XDAQContextTable::DMTypeClassNames_ = { "ots::DataManagerSupervisor", "ots::FEDataManagerSupervisor", "ots::ARTDAQFEDataManagerSupervisor"};
21 const std::set<std::string> XDAQContextTable::LogbookTypeClassNames_ = { "ots::LogbookSupervisor"};
22 const std::set<std::string> XDAQContextTable::MacroMakerTypeClassNames_ = { "ots::MacroMakerSupervisor"};
23 const std::set<std::string> XDAQContextTable::ChatTypeClassNames_ = { "ots::ChatSupervisor"};
24 const std::set<std::string> XDAQContextTable::ConsoleTypeClassNames_ = { "ots::ConsoleSupervisor"};
25 const std::set<std::string> XDAQContextTable::ConfigurationGUITypeClassNames_ = { "ots::TableGUISupervisor"};
26 
27 
28 const uint8_t XDAQContextTable::XDAQApplication::DEFAULT_PRIORITY = 100;
29 
30 XDAQContextTable::ColContext XDAQContextTable::colContext_ = XDAQContextTable::ColContext(); // initialize static member
31 XDAQContextTable::ColApplication XDAQContextTable::colApplication_ = XDAQContextTable::ColApplication(); // initialize static member
32 XDAQContextTable::ColApplicationProperty XDAQContextTable::colAppProperty_ = XDAQContextTable::ColApplicationProperty(); // initialize static member
33 
34 const std::string XDAQContextTable::XDAQ_CONTEXT_TABLE = "XDAQContextTable";
35 
36 
37 // clang-format on
38 
39 //========================================================================================================================
40 XDAQContextTable::XDAQContextTable(void) : TableBase(XDAQContextTable::XDAQ_CONTEXT_TABLE)
41 {
43  // WARNING: the names used in C++ MUST match the Table INFO //
45 }
46 
47 //========================================================================================================================
48 XDAQContextTable::~XDAQContextTable(void) {}
49 
50 //========================================================================================================================
51 void XDAQContextTable::init(ConfigurationManager* configManager)
52 {
53  //__COUT__ << "init" << __E__;
54  extractContexts(configManager);
55 
56  bool isFirstAppInContext = configManager->isOwnerFirstAppInContext();
57 
58  //__COUTV__(isFirstAppInContext);
59  if(!isFirstAppInContext)
60  return;
61 
62 
63  {
65  // generate xdaq run parameter file
66  std::fstream fs;
67  fs.open(XDAQ_RUN_FILE, std::fstream::out | std::fstream::trunc);
68  if(fs.fail())
69  {
70  __SS__ << "Failed to open XDAQ run file: " << XDAQ_RUN_FILE << __E__;
71  __SS_THROW__;
72  }
73  outputXDAQXML((std::ostream&)fs);
74  fs.close();
75  }
76 }
77 
78 //========================================================================================================================
79 std::string XDAQContextTable::getContextAddress(const std::string& contextUID,
80  bool wantHttp) const
81 {
82  if(contextUID == "X")
83  return "";
84  for(auto& context : contexts_)
85  {
86  if(context.contextUID_ == contextUID)
87  {
88  if(wantHttp)
89  return context.address_;
90  auto address = context.address_;
91  if(address.find("http://") == 0)
92  {
93  address = address.replace(0, 7, "");
94  }
95  if(address.find("https://") == 0)
96  {
97  address = address.replace(0, 8, "");
98  }
99  return address;
100  }
101  }
102  return "";
103 } // end getContextAddress()
104 
105 //========================================================================================================================
106 std::vector<const XDAQContextTable::XDAQContext*>
107 XDAQContextTable::getARTDAQSupervisorContexts() const
108 {
109  std::vector<const XDAQContext*> retVec;
110  for(auto& i : artdaqSupervisors_)
111  retVec.push_back(&contexts_[i]);
112  return retVec;
113 }
114 
115 //========================================================================================================================
116 ConfigurationTree XDAQContextTable::getContextNode(
117  const ConfigurationManager* configManager, const std::string& contextUID)
118 {
119  return configManager->getNode(XDAQContextTable::XDAQ_CONTEXT_TABLE).getNode(contextUID);
120 }
121 
122 //========================================================================================================================
123 ConfigurationTree XDAQContextTable::getApplicationNode(
124  const ConfigurationManager* configManager,
125  const std::string& contextUID,
126  const std::string& appUID)
127 {
128  return configManager->getNode(XDAQContextTable::XDAQ_CONTEXT_TABLE).getNode(
129  contextUID + "/" + colContext_.colLinkToApplicationTable_ + "/" + appUID);
130 }
131 
132 //========================================================================================================================
133 ConfigurationTree XDAQContextTable::getSupervisorConfigNode(
134  const ConfigurationManager* configManager,
135  const std::string& contextUID,
136  const std::string& appUID)
137 {
138  return configManager->getNode(XDAQContextTable::XDAQ_CONTEXT_TABLE).getNode(
139  contextUID + "/" + XDAQContextTable::colContext_.colLinkToApplicationTable_ +
140  "/" + appUID + "/" +
141  XDAQContextTable::colApplication_.colLinkToSupervisorTable_);
142 }
143 
144 //========================================================================================================================
145 // extractContexts
146 // Could be called by other tables if they need to access the context.
147 // This doesn't re-write config files, it just re-makes constructs in software.
148 void XDAQContextTable::extractContexts(ConfigurationManager* configManager)
149 {
150  //__COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << __E__;
151  //__COUT__ << configManager->__SELF_NODE__ << __E__;
152 
153  // __COUT__ << configManager->getNode(this->getTableName()).getValueAsString()
154  // << __E__;
155 
156  auto children = configManager->__SELF_NODE__.getChildren();
157 
158  contexts_.clear(); // reset
159  // artdaqContexts_.clear();
160 
161  artdaqSupervisors_.clear();
162 
163  artdaqBoardReaders_.clear();
164  // artdaqEventBuilders_.clear();
165  // artdaqDataLoggers_.clear();
166  // artdaqDispatchers_.clear();
167 
168  // Enforce that app IDs do not repeat!
169  // Note: this is important because there are maps in MacroMaker and
170  // SupervisorDescriptorInfoBase that rely on localId() as key
171  std::set<unsigned int /*appId*/> appIdSet;
172 
173  for(auto& child : children)
174  {
175  contexts_.push_back(XDAQContext());
176  //__COUT__ << child.first << __E__;
177  // __COUT__ << child.second.getNode(colContextUID_) << __E__;
178 
179  contexts_.back().contextUID_ = child.first;
180 
181  contexts_.back().sourceConfig_ =
182  child.second.getTableName() + "_v" +
183  child.second.getTableVersion().toString() + " @ " +
184  std::to_string(child.second.getTableCreationTime());
185  child.second.getNode(colContext_.colContextUID_)
186  .getValue(contexts_.back().contextUID_);
187  child.second.getNode(colContext_.colStatus_).getValue(contexts_.back().status_);
188  child.second.getNode(colContext_.colId_).getValue(contexts_.back().id_);
189  child.second.getNode(colContext_.colAddress_).getValue(contexts_.back().address_);
190  child.second.getNode(colContext_.colPort_).getValue(contexts_.back().port_);
191  // conversion to default happens at TableView.icc
192  // if(contexts_.back().port_ == 0) //convert 0 to ${OTS_MAIN_PORT}
193  // contexts_.back().port_ = atoi(__ENV__("OTS_MAIN_PORT"));
194  if(contexts_.back().port_ < 1024 || contexts_.back().port_ > 49151)
195  {
196  __SS__ << "Illegal xdaq Context port: " << contexts_.back().port_
197  << ". Port must be between 1024 and 49151." << __E__;
198  }
199  // child.second.getNode(colContext_.colARTDAQDataPort_).getValue(contexts_.back().artdaqDataPort_);
200 
201  //__COUT__ << contexts_.back().address_ << __E__;
202  auto appLink = child.second.getNode(colContext_.colLinkToApplicationTable_);
203  if(appLink.isDisconnected())
204  {
205  __SS__ << "Application link is disconnected!" << __E__;
206  __SS_THROW__;
207  }
208 
209  // add xdaq applications to this context
210  auto appChildren = appLink.getChildren();
211  for(auto appChild : appChildren)
212  {
213  //__COUT__ << "Loop: " << child.first << "/" << appChild.first << __E__;
214 
215  contexts_.back().applications_.push_back(XDAQApplication());
216 
217  contexts_.back().applications_.back().applicationGroupID_ = child.first;
218  contexts_.back().applications_.back().sourceConfig_ =
219  appChild.second.getTableName() + "_v" +
220  appChild.second.getTableVersion().toString() + " @ " +
221  std::to_string(appChild.second.getTableCreationTime());
222 
223  appChild.second.getNode(colApplication_.colApplicationUID_)
224  .getValue(contexts_.back().applications_.back().applicationUID_);
225  appChild.second.getNode(colApplication_.colStatus_)
226  .getValue(contexts_.back().applications_.back().status_);
227  appChild.second.getNode(colApplication_.colClass_)
228  .getValue(contexts_.back().applications_.back().class_);
229  appChild.second.getNode(colApplication_.colId_)
230  .getValue(contexts_.back().applications_.back().id_);
231 
232  // assert Gateway is 200
233  if((contexts_.back().applications_.back().id_ == 200 &&
234  contexts_.back().applications_.back().class_ !=
235  XDAQContextTable::GATEWAY_SUPERVISOR_CLASS &&
236  contexts_.back().applications_.back().class_ !=
237  XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS) ||
238  (contexts_.back().applications_.back().id_ != 200 &&
239  (contexts_.back().applications_.back().class_ ==
240  XDAQContextTable::GATEWAY_SUPERVISOR_CLASS ||
241  contexts_.back().applications_.back().class_ ==
242  XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS)))
243  {
244  __SS__ << "XDAQ Application ID of 200 is reserved for the Gateway "
245  "Supervisor "
246  << XDAQContextTable::GATEWAY_SUPERVISOR_CLASS
247  << ". Conflict specifically at id="
248  << contexts_.back().applications_.back().id_ << " appName="
249  << contexts_.back().applications_.back().applicationUID_ << __E__;
250  __SS_THROW__;
251  }
252 
253  // assert NO app id repeats if context/app enabled
254  if(contexts_.back().status_ && contexts_.back().applications_.back().status_)
255  {
256  // assert NO app id repeats
257  if(appIdSet.find(contexts_.back().applications_.back().id_) !=
258  appIdSet.end())
259  {
260  __SS__ << "XDAQ Application IDs are not unique. Specifically at id="
261  << contexts_.back().applications_.back().id_ << " appName="
262  << contexts_.back().applications_.back().applicationUID_
263  << __E__;
264  __COUT_ERR__ << "\n" << ss.str();
265  __SS_THROW__;
266  }
267  appIdSet.insert(contexts_.back().applications_.back().id_);
268  }
269 
270  // convert defaults to values
271  if(appChild.second.getNode(colApplication_.colInstance_).isDefaultValue())
272  contexts_.back().applications_.back().instance_ = 1;
273  else
274  appChild.second.getNode(colApplication_.colInstance_)
275  .getValue(contexts_.back().applications_.back().instance_);
276 
277  if(appChild.second.getNode(colApplication_.colNetwork_).isDefaultValue())
278  contexts_.back().applications_.back().network_ = "local";
279  else
280  appChild.second.getNode(colApplication_.colNetwork_)
281  .getValue(contexts_.back().applications_.back().network_);
282 
283  if(appChild.second.getNode(colApplication_.colGroup_).isDefaultValue())
284  contexts_.back().applications_.back().group_ = "daq";
285  else
286  appChild.second.getNode(colApplication_.colGroup_)
287  .getValue(contexts_.back().applications_.back().group_);
288 
289  appChild.second.getNode(colApplication_.colModule_)
290  .getValue(contexts_.back().applications_.back().module_);
291 
292  // force deprecated Supervisor to GatewaySupervisor class
293  if(contexts_.back().applications_.back().class_ ==
294  XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS)
295  {
296  contexts_.back().applications_.back().class_ =
297  XDAQContextTable::GATEWAY_SUPERVISOR_CLASS;
298  __COUT__ << "Fixing deprecated Supervisor class from "
299  << XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS << " to "
300  << (contexts_.back().applications_.back().class_);
301  }
302  if(contexts_.back().applications_.back().module_.find("libSupervisor.so") !=
303  std::string::npos)
304  {
305  __COUT__ << "Fixing deprecated Supervisor class from "
306  << contexts_.back().applications_.back().module_ << " to ";
307  contexts_.back().applications_.back().module_ =
308  contexts_.back().applications_.back().module_.substr(
309  0,
310  contexts_.back().applications_.back().module_.size() -
311  std::string("Supervisor.so").size()) +
312  "GatewaySupervisor.so";
313  std::cout << contexts_.back().applications_.back().module_ << __E__;
314  }
315 
316  try
317  {
318  appChild.second.getNode(colApplication_.colConfigurePriority_)
319  .getValue(contexts_.back()
320  .applications_.back()
321  .stateMachineCommandPriority_["Configure"]);
322  appChild.second.getNode(colApplication_.colStartPriority_)
323  .getValue(contexts_.back()
324  .applications_.back()
325  .stateMachineCommandPriority_["Start"]);
326  appChild.second.getNode(colApplication_.colStopPriority_)
327  .getValue(contexts_.back()
328  .applications_.back()
329  .stateMachineCommandPriority_["Stop"]);
330  }
331  catch(...)
332  {
333  __COUT__ << "Ignoring missing state machine priorities..." << __E__;
334  }
335 
336  auto appPropertyLink =
337  appChild.second.getNode(colApplication_.colLinkToPropertyTable_);
338  if(!appPropertyLink.isDisconnected())
339  {
340  // add xdaq application properties to this context
341 
342  auto appPropertyChildren = appPropertyLink.getChildren();
343 
344  //__COUT__ << "appPropertyChildren.size() " << appPropertyChildren.size()
345  //<< __E__;
346 
347  for(auto appPropertyChild : appPropertyChildren)
348  {
349  contexts_.back().applications_.back().properties_.push_back(
350  XDAQApplicationProperty());
351  contexts_.back().applications_.back().properties_.back().status_ =
352  appPropertyChild.second.getNode(colAppProperty_.colStatus_)
353  .getValue<bool>();
354  contexts_.back().applications_.back().properties_.back().name_ =
355  appPropertyChild.second.getNode(colAppProperty_.colPropertyName_)
356  .getValue<std::string>();
357  contexts_.back().applications_.back().properties_.back().type_ =
358  appPropertyChild.second.getNode(colAppProperty_.colPropertyType_)
359  .getValue<std::string>();
360  contexts_.back().applications_.back().properties_.back().value_ =
361  appPropertyChild.second.getNode(colAppProperty_.colPropertyValue_)
362  .getValue<std::string>();
363 
364  //__COUT__ <<
365  // contexts_.back().applications_.back().properties_.back().name_ <<
366  // __E__;
367  }
368  }
369  // else
370  // __COUT__ << "Disconnected." << __E__;
371  }
372 
373  // check artdaq type
374  //if(isARTDAQContext(contexts_.back().contextUID_))
375  {
376  // artdaqContexts_.push_back(contexts_.size() - 1);
377 
378  // if(contexts_.back().applications_.size() != 1)
379  // {
380  // __SS__ << "ARTDAQ Context '" << contexts_.back().contextUID_
381  // << "' must have one Application! "
382  // << contexts_.back().applications_.size() << " were found. "
383  // << __E__;
384  // __SS_THROW__;
385  // }
386 
387  if(!contexts_.back().status_)
388  continue; // skip if disabled
389 
390 
391 // if(contexts_.back().applications_[0].class_ == // if board reader
392 // "ots::ARTDAQDataManagerSupervisor" ||
393 // contexts_.back().applications_[0].class_ == // if board reader
394 // "ots::ARTDAQFEDataManagerSupervisor")
395 // artdaqBoardReaders_.push_back(contexts_.size() - 1);
396 
397  for(auto& app : contexts_.back().applications_)
398  {
399  if(app.class_ == // if artdaq interface supervisor
400  "ots::ARTDAQSupervisor")
401  {
402  __COUT__ << "Found " << app.class_ << " in context '" <<
403  contexts_.back().id_ << "'" << __E__;
404  artdaqSupervisors_.push_back(contexts_.size() - 1);
405  break;
406  }
407  }
408 
409  // else if(contexts_.back().applications_[0].class_ == // if event
410  //builder "ots::EventBuilderApp")
411  // artdaqEventBuilders_.push_back(contexts_.size() - 1);
412  // else if(contexts_.back().applications_[0].class_ == // if
413  //dataLogger "ots::DataLoggerApp")
414  // artdaqDataLoggers_.push_back(contexts_.size() - 1);
415  // else if(contexts_.back().applications_[0].class_ == // if
416  //dispatcher "ots::DispatcherApp")
417  // artdaqDispatchers_.push_back(contexts_.size() - 1);
418 // else
419 // {
420 // __SS__
421 // << "ARTDAQ Context must have one and only one Application of an allowed class "
422 // "type:\n"
423 // //<< "\tots::ARTDAQDataManagerSupervisor (Board Reader)\n"
424 // //<< "\tots::ARTDAQFEDataManagerSupervisor (Board Reader)\n"
425 // << "\tots::ARTDAQSupervisor (artdaq Interace Supervisor)\n"
426 // // << "\tots::EventBuilderApp (Event Builder)\n"
427 // // << "\tots::DataLoggerApp (Data Logger)\n"
428 // // << "\tots::DispatcherApp (Dispatcher)\n"
429 // << "\nClass found was " << contexts_.back().applications_[0].class_
430 // << __E__;
431 // __SS_THROW__;
432 // }
433  } //end artdaq context handling
434 
435  } //end primary context loop
436 } //end extractContexts()
437 
438 //========================================================================================================================
439 void XDAQContextTable::outputXDAQXML(std::ostream& out)
440 {
441  // each generated context will look something like this:
442  //<xc:Context id="0" url="http://${SUPERVISOR_SERVER}:${PORT}">
446  //</xc:Context>
447 
448  // print xml header information and declare xc partition
449  out << "<?xml version='1.0'?>\n"
450  << "<xc:Partition \txmlns:xsi\t= \"http://www.w3.org/2001/XMLSchema-instance\"\n"
451  << "\t\txmlns:soapenc\t= \"http://schemas.xmlsoap.org/soap/encoding/\"\n"
452  << "\t\txmlns:xc\t= "
453  "\"http://xdaq.web.cern.ch/xdaq/xsd/2004/XMLConfiguration-30\">\n\n";
454 
455  // print partition open
456  // for each context
457  // open context
458  // for each app in context
459  // print application
460  // print module
461  // close context
462  // close partition
463 
464  char tmp[200];
465  for(XDAQContext& context : contexts_)
466  {
467  //__COUT__ << context.contextUID_ << __E__;
468 
469  sprintf(tmp,
470  "\t<!-- ContextUID='%s' sourceConfig='%s' -->",
471  context.contextUID_.c_str(),
472  context.sourceConfig_.c_str());
473  out << tmp << "\n";
474 
475  if(!context.status_) // comment out if disabled
476  out << "\t<!--\n";
477 
478  sprintf(tmp,
479  "\t<xc:Context id=\"%u\" url=\"%s:%u\">",
480  context.id_,
481  context.address_.c_str(),
482  context.port_);
483  out << tmp << "\n\n";
484 
485  for(XDAQApplication& app : context.applications_)
486  {
487  //__COUT__ << app.id_ << __E__;
488 
489  if(context.status_)
490  {
491  sprintf(
492  tmp,
493  "\t\t<!-- Application GroupID = '%s' UID='%s' sourceConfig='%s' -->",
494  app.applicationGroupID_.c_str(),
495  app.applicationUID_.c_str(),
496  app.sourceConfig_.c_str());
497  out << tmp << "\n";
498 
499  if(!app.status_) // comment out if disabled
500  out << "\t\t<!--\n";
501  }
502 
503  sprintf(tmp,
504  "\t\t<xc:Application class=\"%s\" id=\"%u\" instance=\"%u\" "
505  "network=\"%s\" group=\"%s\">\n",
506  app.class_.c_str(),
507  app.id_,
508  app.instance_,
509  app.network_.c_str(),
510  app.group_.c_str());
511  out << tmp;
512 
514  int foundColon = app.class_.rfind(':');
515  if(foundColon >= 0)
516  ++foundColon;
517  else
518  {
519  __SS__ << "Illegal XDAQApplication class name value of '" << app.class_
520  << "' - please check the entry for app ID = " << app.id_ << __E__;
521  __SS_THROW__;
522  }
523  out << "\t\t\t<properties xmlns=\"urn:xdaq-application:"
524  << app.class_.substr(foundColon) << "\" xsi:type=\"soapenc:Struct\">\n";
525 
526  //__COUT__ << "app.properties_ " << app.properties_.size() << __E__;
527  for(XDAQApplicationProperty& appProperty : app.properties_)
528  {
529  if(appProperty.type_ == "ots::SupervisorProperty")
530  continue; // skip ots Property values
531 
532  if(!appProperty.status_)
533  out << "\t\t\t\t<!--\n";
534 
535  sprintf(tmp,
536  "\t\t\t\t<%s xsi:type=\"%s\">%s</%s>\n",
537  appProperty.name_.c_str(),
538  appProperty.type_.c_str(),
539  appProperty.value_.c_str(),
540  appProperty.name_.c_str());
541  out << tmp;
542 
543  if(!appProperty.status_)
544  out << "\t\t\t\t-->\n";
545  }
546  out << "\t\t\t</properties>\n";
548 
549  out << "\t\t</xc:Application>\n";
550 
551  sprintf(tmp, "\t\t<xc:Module>%s</xc:Module>\n", app.module_.c_str());
552  out << tmp;
553 
554  if(context.status_ && !app.status_)
555  out << "\t\t-->\n";
556  out << "\n";
557 
558  // __COUT__ << "DONE" << __E__;
559  }
560 
561  out << "\t</xc:Context>\n";
562  if(!context.status_)
563  out << "\t-->\n";
564  out << "\n";
565  }
566 
567  //__COUT__ << "DONE" << __E__;
568  out << "</xc:Partition>\n\n\n";
569 }
570 
571 //========================================================================================================================
572 std::string XDAQContextTable::getContextUID(const std::string& url) const
573 {
574  for(auto context : contexts_)
575  {
576  if(!context.status_)
577  continue;
578 
579  if(url == context.address_ + ":" + std::to_string(context.port_))
580  return context.contextUID_;
581  }
582  return "";
583 }
584 
585 //========================================================================================================================
586 std::string XDAQContextTable::getApplicationUID(const std::string& url,
587  unsigned int id) const
588 {
589  //__COUTV__(url); __COUTV__(id);
590  for(auto context : contexts_)
591  {
592  //__COUT__ << "Checking " << (context.address_ + ":" +
593  // std::to_string(context.port_)) << __E__;
594  //__COUTV__(context.status_);
595 
596  if(!context.status_)
597  continue;
598 
599  //__COUT__ << "Checking " << (context.address_ + ":" +
600  // std::to_string(context.port_)) << __E__;
601  if(url == context.address_ + ":" + std::to_string(context.port_))
602  for(auto application : context.applications_)
603  {
604  //__COUTV__(application.status_); __COUTV__(application.id_);
605  if(!application.status_)
606  continue;
607 
608  if(application.id_ == id)
609  {
610  return application.applicationUID_;
611  }
612  }
613  }
614  return "";
615 }
616 
617 DEFINE_OTS_TABLE(XDAQContextTable)
void outputXDAQXML(std::ostream &out)