otsdaq  v2_04_01
XDAQContextTable_table.cc
1 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
2 #include "otsdaq-core/Macros/TablePluginMacros.h"
3 #include "otsdaq-core/TablePlugins/XDAQContextTable.h"
4 
5 #include <stdio.h>
6 #include <fstream> // std::fstream
7 #include <iostream>
8 
9 using namespace ots;
10 
11 #define XDAQ_RUN_FILE \
12  std::string(__ENV__("XDAQ_CONFIGURATION_DATA_PATH")) + "/" + \
13  std::string(__ENV__("XDAQ_CONFIGURATION_XML")) + ".xml"
14 #define APP_PRIORITY_FILE \
15  std::string(__ENV__("XDAQ_CONFIGURATION_DATA_PATH")) + "/" + \
16  "xdaqAppStateMachinePriority"
17 
18 //#define XDAQ_SCRIPT std::string(__ENV__("XDAQ_CONFIGURATION_DATA_PATH")) +
19 //"/"+ "StartXDAQ_gen.sh" #define ARTDAQ_MPI_SCRIPT
20 // std::string(__ENV__("XDAQ_CONFIGURATION_DATA_PATH")) + "/"+ "StartMPI_gen.sh"
21 
22 const std::string XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS =
23  "ots::Supervisor"; // still allowed for now, in StartOTS
24 const std::string XDAQContextTable::GATEWAY_SUPERVISOR_CLASS = "ots::GatewaySupervisor";
25 const std::string XDAQContextTable::WIZARD_SUPERVISOR_CLASS = "ots::WizardSupervisor";
26 const std::set<std::string> XDAQContextTable::FETypeClassNames_ = {
27  "ots::FESupervisor",
28  "ots::FEDataManagerSupervisor",
29  "ots::ARTDAQFEDataManagerSupervisor"};
30 const std::set<std::string> XDAQContextTable::DMTypeClassNames_ = {
31  "ots::DataManagerSupervisor",
32  "ots::FEDataManagerSupervisor",
33  "ots::ARTDAQFEDataManagerSupervisor"};
34 const std::set<std::string> XDAQContextTable::LogbookTypeClassNames_ = {
35  "ots::LogbookSupervisor"};
36 const std::set<std::string> XDAQContextTable::MacroMakerTypeClassNames_ = {
37  "ots::MacroMakerSupervisor"};
38 const std::set<std::string> XDAQContextTable::ChatTypeClassNames_ = {
39  "ots::ChatSupervisor"};
40 const std::set<std::string> XDAQContextTable::ConsoleTypeClassNames_ = {
41  "ots::ConsoleSupervisor"};
42 const std::set<std::string> XDAQContextTable::ConfigurationGUITypeClassNames_ = {
43  "ots::TableGUISupervisor"};
44 
45 const std::string XDAQContextTable::ARTDAQ_OFFSET_PORT = "OffsetPort";
46 
47 const uint8_t XDAQContextTable::XDAQApplication::DEFAULT_PRIORITY = 100;
48 
49 //========================================================================================================================
50 XDAQContextTable::XDAQContextTable(void) : TableBase("XDAQContextTable")
51 {
53  // WARNING: the names used in C++ MUST match the Table INFO //
55 }
56 
57 //========================================================================================================================
58 XDAQContextTable::~XDAQContextTable(void) {}
59 
60 //========================================================================================================================
61 void XDAQContextTable::init(ConfigurationManager* configManager)
62 {
63  //__COUT__ << "init" << __E__;
64  extractContexts(configManager);
65 
66  {
68  // generate xdaq run parameter file
69  std::fstream fs;
70  fs.open(XDAQ_RUN_FILE, std::fstream::out | std::fstream::trunc);
71  if(fs.fail())
72  {
73  __SS__ << "Failed to open XDAQ run file: " << XDAQ_RUN_FILE << __E__;
74  __SS_THROW__;
75  }
76  outputXDAQXML((std::ostream&)fs);
77  fs.close();
78  }
79 }
80 
81 //========================================================================================================================
82 // isARTDAQContext
83 bool XDAQContextTable::isARTDAQContext(const std::string& contextUID)
84 {
85  return (contextUID.find("ART") == 0 || contextUID.find("ARTDAQ") == 0);
86 }
87 
88 //========================================================================================================================
89 std::map<std::string /*contextUID*/,
90  std::pair<std::string /*host_name*/, unsigned int /*rank*/>>
91 XDAQContextTable::getARTDAQAppRankMap() const
92 {
93  std::map<std::string /*contextUID*/,
94  std::pair<std::string /*host_name*/, unsigned int /*rank*/>>
95  returnMap;
96 
97  if(artdaqBoardReaders_.size() == 0 && artdaqEventBuilders_.size() == 0 &&
98  artdaqAggregators_.size() == 0)
99  {
100  __COUT_WARN__ << "Assuming since there are 0 active ARTDAQ context UID(s), we "
101  "can ignore empty rank map."
102  << __E__;
103  return returnMap;
104  }
105 
106  for(auto& i : artdaqBoardReaders_)
107  returnMap.emplace(
108  std::make_pair(contexts_[i].contextUID_,
109  std::make_pair(contexts_[i].address_,
110  getARTDAQAppRank(contexts_[i].contextUID_))));
111 
112  for(auto& i : artdaqEventBuilders_)
113  returnMap.emplace(
114  std::make_pair(contexts_[i].contextUID_,
115  std::make_pair(contexts_[i].address_,
116  getARTDAQAppRank(contexts_[i].contextUID_))));
117 
118  for(auto& i : artdaqAggregators_)
119  returnMap.emplace(
120  std::make_pair(contexts_[i].contextUID_,
121  std::make_pair(contexts_[i].address_,
122  getARTDAQAppRank(contexts_[i].contextUID_))));
123 
124  return returnMap;
125 } // end getARTDAQAppRankMap
126 
127 //========================================================================================================================
128 // getARTDAQAppRank
129 // looks through all active artdaq contexts for UID
130 // throws exception if not found
131 //
132 // if contextUID == "X" (which happens automatically for broken link)
133 // then highest possible rank plus 1 is returned
134 unsigned int XDAQContextTable::getARTDAQAppRank(const std::string& contextUID) const
135 {
136  if(artdaqBoardReaders_.size() == 0 && artdaqEventBuilders_.size() == 0 &&
137  artdaqAggregators_.size() == 0)
138  {
139  __COUT_WARN__ << "Assuming since there are 0 active ARTDAQ context UID(s), we "
140  "can ignore rank failure."
141  << __E__;
142  return -1;
143  }
144 
145  // define local "lambda" getRank function
146  auto localGetRank = [](const XDAQContext& context) -> unsigned int {
147  if(context.applications_.size() != 1)
148  {
149  __SS__ << "Invalid number of ARTDAQ applications in context '"
150  << context.contextUID_ << ".' Must be 1. Currently is "
151  << context.applications_.size() << "." << __E__;
152  __SS_THROW__;
153  }
154 
155  return context.applications_[0].id_;
156  };
157 
158  for(auto& i : artdaqBoardReaders_)
159  if(contexts_[i].contextUID_ == contextUID)
160  return localGetRank(contexts_[i]);
161 
162  for(auto& i : artdaqEventBuilders_)
163  if(contexts_[i].contextUID_ == contextUID)
164  return localGetRank(contexts_[i]);
165 
166  for(auto& i : artdaqAggregators_)
167  if(contexts_[i].contextUID_ == contextUID)
168  return localGetRank(contexts_[i]);
169 
170  // if (contextUID == "X")
171  // return -1; //assume disconnected link should not error?
172 
173  __SS__ << "ARTDAQ rank could not be found for context UID '" << contextUID << ".'"
174  << __E__;
175  __SS_THROW__; // should never happen!
176 } // end getARTDAQAppRank()
177 
178 //========================================================================================================================
179 std::string XDAQContextTable::getContextAddress(const std::string& contextUID,
180  bool wantHttp) const
181 {
182  if(contextUID == "X")
183  return "";
184  for(auto& context : contexts_)
185  {
186  if(context.contextUID_ == contextUID)
187  {
188  if(wantHttp)
189  return context.address_;
190  auto address = context.address_;
191  if(address.find("http://") == 0)
192  {
193  address = address.replace(0, 7, "");
194  }
195  if(address.find("https://") == 0)
196  {
197  address = address.replace(0, 8, "");
198  }
199  return address;
200  }
201  }
202  return "";
203 }
204 
205 unsigned int XDAQContextTable::getARTDAQDataPort(
206  const ConfigurationManager* configManager, const std::string& contextUID) const
207 {
208  if(contextUID == "X")
209  return 0;
210  for(auto& context : contexts_)
211  {
212  if(context.contextUID_ == contextUID)
213  {
214  if(context.applications_.size() != 1)
215  {
216  __SS__ << "Invalid number of ARTDAQ applications in context '"
217  << contextUID << ".' Must be 1. Currently is "
218  << context.applications_.size() << "." << __E__;
219  __SS_THROW__;
220  }
221 
222  // Board Reader port is through Processor table
223  if(context.applications_[0].class_ == "ots::ARTDAQDataManagerSupervisor" ||
224  context.applications_[0].class_ == "ots::ARTDAQFEDataManagerSupervisor")
225  {
226  auto processors =
227  getSupervisorConfigNode(configManager,
228  context.contextUID_,
229  context.applications_[0].applicationUID_)
230  .getNode("LinkToDataBufferTable")
231  .getChildren()[0]
232  .second.getNode("LinkToDataProcessorTable")
233  .getChildren();
234 
235  std::string processorType;
236 
237  // take first board reader processor (could be Consumer or Producer)
238  for(auto& processor : processors)
239  {
240  processorType = processor.second.getNode("ProcessorPluginName")
241  .getValue<std::string>();
242  __COUTV__(processorType);
243 
244  if(processorType == "ARTDAQConsumer" ||
245  processorType == "ARTDAQProducer")
246  return processor.second.getNode("LinkToProcessorTable")
247  .getNode(XDAQContextTable::ARTDAQ_OFFSET_PORT)
248  .getValue<unsigned int>();
249  }
250 
251  __SS__ << "No ARTDAQ processor was found while looking for data port."
252  << __E__;
253  __SS_THROW__;
254  }
255  // else, Builder or Aggregator
256  return getSupervisorConfigNode(configManager,
257  context.contextUID_,
258  context.applications_[0].applicationUID_)
259  .getNode(XDAQContextTable::ARTDAQ_OFFSET_PORT)
260  .getValue<unsigned int>();
261  }
262  }
263  return 0;
264 }
265 
266 //========================================================================================================================
267 std::vector<const XDAQContextTable::XDAQContext*>
268 XDAQContextTable::getBoardReaderContexts() const
269 {
270  std::vector<const XDAQContext*> retVec;
271  for(auto& i : artdaqBoardReaders_)
272  retVec.push_back(&contexts_[i]);
273  return retVec;
274 }
275 //========================================================================================================================
276 std::vector<const XDAQContextTable::XDAQContext*>
277 XDAQContextTable::getEventBuilderContexts() const
278 {
279  std::vector<const XDAQContext*> retVec;
280  for(auto& i : artdaqEventBuilders_)
281  retVec.push_back(&contexts_[i]);
282  return retVec;
283 }
284 //========================================================================================================================
285 std::vector<const XDAQContextTable::XDAQContext*>
286 XDAQContextTable::getAggregatorContexts() const
287 {
288  std::vector<const XDAQContext*> retVec;
289  for(auto& i : artdaqAggregators_)
290  retVec.push_back(&contexts_[i]);
291  return retVec;
292 }
293 
294 //========================================================================================================================
295 ConfigurationTree XDAQContextTable::getContextNode(
296  const ConfigurationManager* configManager, const std::string& contextUID) const
297 {
298  return configManager->__SELF_NODE__.getNode(contextUID);
299 }
300 
301 //========================================================================================================================
302 ConfigurationTree XDAQContextTable::getApplicationNode(
303  const ConfigurationManager* configManager,
304  const std::string& contextUID,
305  const std::string& appUID) const
306 {
307  return configManager->__SELF_NODE__.getNode(
308  contextUID + "/" + colContext_.colLinkToApplicationTable_ + "/" + appUID);
309 }
310 
311 //========================================================================================================================
312 ConfigurationTree XDAQContextTable::getSupervisorConfigNode(
313  const ConfigurationManager* configManager,
314  const std::string& contextUID,
315  const std::string& appUID) const
316 {
317  return configManager->__SELF_NODE__.getNode(
318  contextUID + "/" + colContext_.colLinkToApplicationTable_ + "/" + appUID + "/" +
319  colApplication_.colLinkToSupervisorTable_);
320 }
321 
322 //========================================================================================================================
323 // extractContexts
324 // Could be called by other tables if they need to access the context.
325 // This doesn't re-write config files, it just re-makes constructs in software.
326 void XDAQContextTable::extractContexts(ConfigurationManager* configManager)
327 {
328  //__COUT__ << "*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*" << __E__;
329  //__COUT__ << configManager->__SELF_NODE__ << __E__;
330 
331  // __COUT__ << configManager->getNode(this->getTableName()).getValueAsString()
332  // << __E__;
333 
334  auto children = configManager->__SELF_NODE__.getChildren();
335 
336  contexts_.clear(); // reset
337  // artdaqContexts_.clear();
338 
339  artdaqBoardReaders_.clear();
340  artdaqEventBuilders_.clear();
341  artdaqAggregators_.clear();
342 
343  // Enforce that app IDs do not repeat!
344  // Note: this is important because there are maps in MacroMaker and
345  // SupervisorDescriptorInfoBase that rely on localId() as key
346  std::set<unsigned int /*appId*/> appIdSet;
347 
348  for(auto& child : children)
349  {
350  contexts_.push_back(XDAQContext());
351  //__COUT__ << child.first << __E__;
352  // __COUT__ << child.second.getNode(colContextUID_) << __E__;
353 
354  contexts_.back().contextUID_ = child.first;
355 
356  contexts_.back().sourceConfig_ =
357  child.second.getTableName() + "_v" +
358  child.second.getTableVersion().toString() + " @ " +
359  std::to_string(child.second.getTableCreationTime());
360  child.second.getNode(colContext_.colContextUID_)
361  .getValue(contexts_.back().contextUID_);
362  child.second.getNode(colContext_.colStatus_).getValue(contexts_.back().status_);
363  child.second.getNode(colContext_.colId_).getValue(contexts_.back().id_);
364  child.second.getNode(colContext_.colAddress_).getValue(contexts_.back().address_);
365  child.second.getNode(colContext_.colPort_).getValue(contexts_.back().port_);
366  // child.second.getNode(colContext_.colARTDAQDataPort_).getValue(contexts_.back().artdaqDataPort_);
367 
368  //__COUT__ << contexts_.back().address_ << __E__;
369  auto appLink = child.second.getNode(colContext_.colLinkToApplicationTable_);
370  if(appLink.isDisconnected())
371  {
372  __SS__ << "Application link is disconnected!" << __E__;
373  __SS_THROW__;
374  }
375 
376  // add xdaq applications to this context
377  auto appChildren = appLink.getChildren();
378  for(auto appChild : appChildren)
379  {
380  //__COUT__ << "Loop: " << child.first << "/" << appChild.first << __E__;
381 
382  contexts_.back().applications_.push_back(XDAQApplication());
383 
384  contexts_.back().applications_.back().applicationGroupID_ = child.first;
385  contexts_.back().applications_.back().sourceConfig_ =
386  appChild.second.getTableName() + "_v" +
387  appChild.second.getTableVersion().toString() + " @ " +
388  std::to_string(appChild.second.getTableCreationTime());
389 
390  appChild.second.getNode(colApplication_.colApplicationUID_)
391  .getValue(contexts_.back().applications_.back().applicationUID_);
392  appChild.second.getNode(colApplication_.colStatus_)
393  .getValue(contexts_.back().applications_.back().status_);
394  appChild.second.getNode(colApplication_.colClass_)
395  .getValue(contexts_.back().applications_.back().class_);
396  appChild.second.getNode(colApplication_.colId_)
397  .getValue(contexts_.back().applications_.back().id_);
398 
399  // assert Gateway is 200
400  if((contexts_.back().applications_.back().id_ == 200 &&
401  contexts_.back().applications_.back().class_ !=
402  XDAQContextTable::GATEWAY_SUPERVISOR_CLASS &&
403  contexts_.back().applications_.back().class_ !=
404  XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS) ||
405  (contexts_.back().applications_.back().id_ != 200 &&
406  (contexts_.back().applications_.back().class_ ==
407  XDAQContextTable::GATEWAY_SUPERVISOR_CLASS ||
408  contexts_.back().applications_.back().class_ ==
409  XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS)))
410  {
411  __SS__ << "XDAQ Application ID of 200 is reserved for the Gateway "
412  "Supervisor "
413  << XDAQContextTable::GATEWAY_SUPERVISOR_CLASS
414  << ". Conflict specifically at id="
415  << contexts_.back().applications_.back().id_ << " appName="
416  << contexts_.back().applications_.back().applicationUID_ << __E__;
417  __SS_THROW__;
418  }
419 
420  // assert NO app id repeats if context/app enabled
421  if(contexts_.back().status_ && contexts_.back().applications_.back().status_)
422  {
423  // assert NO app id repeats
424  if(appIdSet.find(contexts_.back().applications_.back().id_) !=
425  appIdSet.end())
426  {
427  __SS__ << "XDAQ Application IDs are not unique. Specifically at id="
428  << contexts_.back().applications_.back().id_ << " appName="
429  << contexts_.back().applications_.back().applicationUID_
430  << __E__;
431  __COUT_ERR__ << "\n" << ss.str();
432  __SS_THROW__;
433  }
434  appIdSet.insert(contexts_.back().applications_.back().id_);
435  }
436 
437  // convert defaults to values
438  if(appChild.second.getNode(colApplication_.colInstance_).isDefaultValue())
439  contexts_.back().applications_.back().instance_ = 1;
440  else
441  appChild.second.getNode(colApplication_.colInstance_)
442  .getValue(contexts_.back().applications_.back().instance_);
443 
444  if(appChild.second.getNode(colApplication_.colNetwork_).isDefaultValue())
445  contexts_.back().applications_.back().network_ = "local";
446  else
447  appChild.second.getNode(colApplication_.colNetwork_)
448  .getValue(contexts_.back().applications_.back().network_);
449 
450  if(appChild.second.getNode(colApplication_.colGroup_).isDefaultValue())
451  contexts_.back().applications_.back().group_ = "daq";
452  else
453  appChild.second.getNode(colApplication_.colGroup_)
454  .getValue(contexts_.back().applications_.back().group_);
455 
456  appChild.second.getNode(colApplication_.colModule_)
457  .getValue(contexts_.back().applications_.back().module_);
458 
459  // force deprecated Supervisor to GatewaySupervisor class
460  if(contexts_.back().applications_.back().class_ ==
461  XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS)
462  {
463  contexts_.back().applications_.back().class_ =
464  XDAQContextTable::GATEWAY_SUPERVISOR_CLASS;
465  __COUT__ << "Fixing deprecated Supervisor class from "
466  << XDAQContextTable::DEPRECATED_SUPERVISOR_CLASS << " to "
467  << (contexts_.back().applications_.back().class_);
468  }
469  if(contexts_.back().applications_.back().module_.find("libSupervisor.so") !=
470  std::string::npos)
471  {
472  __COUT__ << "Fixing deprecated Supervisor class from "
473  << contexts_.back().applications_.back().module_ << " to ";
474  contexts_.back().applications_.back().module_ =
475  contexts_.back().applications_.back().module_.substr(
476  0,
477  contexts_.back().applications_.back().module_.size() -
478  std::string("Supervisor.so").size()) +
479  "GatewaySupervisor.so";
480  std::cout << contexts_.back().applications_.back().module_ << __E__;
481  }
482 
483  try
484  {
485  appChild.second.getNode(colApplication_.colConfigurePriority_)
486  .getValue(contexts_.back()
487  .applications_.back()
488  .stateMachineCommandPriority_["Configure"]);
489  appChild.second.getNode(colApplication_.colStartPriority_)
490  .getValue(contexts_.back()
491  .applications_.back()
492  .stateMachineCommandPriority_["Start"]);
493  appChild.second.getNode(colApplication_.colStopPriority_)
494  .getValue(contexts_.back()
495  .applications_.back()
496  .stateMachineCommandPriority_["Stop"]);
497  }
498  catch(...)
499  {
500  __COUT__ << "Ignoring missing state machine priorities..." << __E__;
501  }
502 
503  auto appPropertyLink =
504  appChild.second.getNode(colApplication_.colLinkToPropertyTable_);
505  if(!appPropertyLink.isDisconnected())
506  {
507  // add xdaq application properties to this context
508 
509  auto appPropertyChildren = appPropertyLink.getChildren();
510 
511  //__COUT__ << "appPropertyChildren.size() " << appPropertyChildren.size()
512  //<< __E__;
513 
514  for(auto appPropertyChild : appPropertyChildren)
515  {
516  contexts_.back().applications_.back().properties_.push_back(
517  XDAQApplicationProperty());
518  contexts_.back().applications_.back().properties_.back().status_ =
519  appPropertyChild.second.getNode(colAppProperty_.colStatus_)
520  .getValue<bool>();
521  contexts_.back().applications_.back().properties_.back().name_ =
522  appPropertyChild.second.getNode(colAppProperty_.colPropertyName_)
523  .getValue<std::string>();
524  contexts_.back().applications_.back().properties_.back().type_ =
525  appPropertyChild.second.getNode(colAppProperty_.colPropertyType_)
526  .getValue<std::string>();
527  contexts_.back().applications_.back().properties_.back().value_ =
528  appPropertyChild.second.getNode(colAppProperty_.colPropertyValue_)
529  .getValue<std::string>();
530 
531  //__COUT__ <<
532  // contexts_.back().applications_.back().properties_.back().name_ <<
533  // __E__;
534  }
535  }
536  // else
537  // __COUT__ << "Disconnected." << __E__;
538  }
539 
540  // check artdaq type
541  if(isARTDAQContext(contexts_.back().contextUID_))
542  {
543  // artdaqContexts_.push_back(contexts_.size() - 1);
544 
545  if(contexts_.back().applications_.size() != 1)
546  {
547  __SS__ << "ARTDAQ Context '" << contexts_.back().contextUID_
548  << "' must have one Application! "
549  << contexts_.back().applications_.size() << " were found. "
550  << __E__;
551  __SS_THROW__;
552  }
553 
554  if(!contexts_.back().status_)
555  continue; // skip if disabled
556 
557  if(contexts_.back().applications_[0].class_ == // if board reader
558  "ots::ARTDAQDataManagerSupervisor" ||
559  contexts_.back().applications_[0].class_ == // if board reader
560  "ots::ARTDAQFEDataManagerSupervisor")
561  artdaqBoardReaders_.push_back(contexts_.size() - 1);
562  else if(contexts_.back().applications_[0].class_ == // if event builder
563  "ots::EventBuilderApp")
564  artdaqEventBuilders_.push_back(contexts_.size() - 1);
565  else if(contexts_.back().applications_[0].class_ == // if aggregator
566  "ots::DataLoggerApp" ||
567  contexts_.back().applications_[0].class_ == // if aggregator
568  "ots::DispatcherApp")
569  artdaqAggregators_.push_back(contexts_.size() - 1);
570  else
571  {
572  __SS__ << "ARTDAQ Context must be have Application of an allowed class "
573  "type:\n"
574  << "\tots::ARTDAQDataManagerSupervisor (Board Reader)\n"
575  << "\tots::ARTDAQFEDataManagerSupervisor (Board Reader)\n"
576  << "\tots::EventBuilderApp (Event Builder)\n"
577  << "\tots::DataLoggerApp (Aggregator)\n"
578  << "\tots::DispatcherApp (Aggregator)\n"
579  << "\nClass found was " << contexts_.back().applications_[0].class_
580  << __E__;
581  __SS_THROW__;
582  }
583  }
584  }
585 }
586 
587 //========================================================================================================================
588 // void XDAQContextTable::outputXDAQScript(std::ostream &out)
589 //{
590 /*
591  the file will look something like this:
592  #!/bin/sh
593 
594  echo
595  echo
596 
597  echo "Launching XDAQ contexts..."
598 
599  #for each XDAQ context
600  xdaq.exe -p ${CONTEXT_PORT} -e ${XDAQ_ARGS} &
601 
602  */
603 
604 // out << "#!/bin/sh\n\n";
605 //
606 // out << "echo\necho\n\n";
607 //
608 // out << "echo \"Launching XDAQ contexts...\"\n\n";
609 // out << "#for each XDAQ context\n";
610 //
611 //
612 // std::stringstream ss;
613 // int count = 0;
614 // //for each non-"ART" or "ARTDAQ" context make a xdaq entry
615 // for(XDAQContext &context:contexts_)
616 // {
617 // if(isARTDAQContext(context.contextUID_))
618 // continue; //skip if UID does identify as artdaq
619 //
620 // if(!context.status_)
621 // continue; //skip if disabled
622 //
623 // //at this point we have a xdaq context.. so make an xdaq entry
624 //
625 // ++count;
626 // ss << "echo \"xdaq.exe -p " <<
627 // context.port_ << " -e ${XDAQ_ARGS} &\"\n";
628 // ss << "xdaq.exe -p " <<
629 // context.port_ << " -e ${XDAQ_ARGS} & " <<
630 // "#" << context.contextUID_ << "\n";
631 // }
632 //
633 //
634 // if(count == 0) //if no artdaq contexts at all
635 // {
636 // out << "echo \"No XDAQ (non-artdaq) contexts found.\"\n\n";
637 // out << "echo\necho\n";
638 // return;
639 // }
640 //
641 // out << ss.str();
642 //
643 // out << "\n\n";
644 //}
645 
647 // void XDAQContextTable::outputARTDAQScript(std::ostream &out)
648 //{
649 /*
650  the file will look something like this:
651  #!/bin/sh
652 
653 
654  echo
655  echo
656  while [ 1 ]; do
657 
658  echo "Cleaning up old MPI instance..."
659  killall mpirun
660 
661 
662  echo "Starting mpi run..."
663  echo "$1"
664  echo
665  echo
666 
667  echo mpirun $1 \
668  -np 1 xdaq.exe -p ${ARTDAQ_BOARDREADER_PORT1} -e ${XDAQ_ARGS} :
669  \
670  -np 1 xdaq.exe -p ${ARTDAQ_BOARDREADER_PORT2} -e ${XDAQ_ARGS} :
671  \
672  -np 1 xdaq.exe -p ${ARTDAQ_BUILDER_PORT} -e ${XDAQ_ARGS} :
673  \ -np 1 xdaq.exe -p ${ARTDAQ_AGGREGATOR_PORT} -e ${XDAQ_ARGS} &
674 
675  echo
676  echo
677 
678  ret=mpirun $1 \
679  -np 1 xdaq.exe -p ${ARTDAQ_BOARDREADER_PORT1} -e ${XDAQ_ARGS} : \
680  -np 1 xdaq.exe -p ${ARTDAQ_BOARDREADER_PORT2} -e ${XDAQ_ARGS} : \
681  -np 1 xdaq.exe -p ${ARTDAQ_BUILDER_PORT} -e ${XDAQ_ARGS} : \
682  -np 1 xdaq.exe -p ${ARTDAQ_AGGREGATOR_PORT} -e ${XDAQ_ARGS}
683 
684  if [ $ret -eq 0 ]; then
685  exit
686  fi
687 
688  done
689  */
690 
691 // __COUT__ << artdaqContexts_.size() << " total artdaq context(s)." << __E__;
692 // __COUT__ << artdaqBoardReaders_.size() << " active artdaq board reader(s)." <<
693 // __E__;
694 // __COUT__ << artdaqEventBuilders_.size() << " active artdaq event builder(s)." <<
695 // __E__;
696 // __COUT__ << artdaqAggregators_.size() << " active artdaq aggregator(s)." << __E__;
697 //
698 // out << "#!/bin/sh\n\n";
699 //
700 // out << "\techo\n\techo\n\n";
701 // //out << "while [ 1 ]; do\n\n";
702 //
703 // //out << "\techo \"Cleaning up old MPI instance...\"\n";
704 //
705 // out << "\techo \"" <<
706 // artdaqContexts_.size() << " artdaq Contexts." <<
707 // "\"\n";
708 // out << "\techo \"\t" <<
709 // artdaqBoardReaders_.size() << " artdaq board readers." <<
710 // "\"\n";
711 // out << "\techo \"\t" <<
712 // artdaqEventBuilders_.size() << " artdaq event builders." <<
713 // "\"\n";
714 // out << "\techo \"\t" <<
715 // artdaqAggregators_.size() << " artdaq aggregators_." <<
716 // "\"\n";
717 //
718 // //out << "\tkillall mpirun\n";
719 // out << "\techo\n\techo\n\n";
720 //
721 // out << "\techo \"Starting mpi run...\"\n";
722 // out << "\techo \"$1\"\n\techo\n\techo\n\n";
723 //
724 //
725 //
726 // std::stringstream ss,ssUID;
727 // int count = 0;
728 //
729 // //ss << "\tret=`mpirun $1 \\\n"; `
730 //
731 // ss << "\tmpirun $1 \\\n";
732 //
733 // //for each "ART" or "ARTDAQ" context make an mpi entry
734 // //make an mpi entry for board readers, then event builders, then aggregators
735 //
736 // for(auto &i:artdaqBoardReaders_)
737 // {
738 // if(count++) //add line breaks if not first context
739 // ss << ": \\\n";
740 //
741 // ss << " -np 1 xdaq.exe -p " <<
742 // contexts_[i].port_ << " -e ${XDAQ_ARGS} ";
743 //
744 // ssUID << "\n\t#board reader \t context.port_ \t " << contexts_[i].port_ <<
745 // ": \t" << contexts_[i].contextUID_;
746 // }
747 //
748 // for(auto &i:artdaqEventBuilders_)
749 // {
750 // if(count++) //add line breaks if not first context
751 // ss << ": \\\n";
752 //
753 // ss << " -np 1 xdaq.exe -p " <<
754 // contexts_[i].port_ << " -e ${XDAQ_ARGS} ";
755 //
756 // ssUID << "\n\t#event builder \t context.port_ \t " << contexts_[i].port_ <<
757 // ": \t" << contexts_[i].contextUID_;
758 // }
759 //
760 // for(auto &i:artdaqAggregators_)
761 // {
762 // if(count++) //add line breaks if not first context
763 // ss << ": \\\n";
764 //
765 // ss << " -np 1 xdaq.exe -p " <<
766 // contexts_[i].port_ << " -e ${XDAQ_ARGS} ";
767 //
768 // ssUID << "\n\t#aggregator \t context.port_ \t " << contexts_[i].port_ <<
769 // ": \t" << contexts_[i].contextUID_;
770 // }
771 //
772 //
773 // if(count == 0) //if no artdaq contexts at all
774 // {
775 // out << "\techo \"No ARTDAQ contexts found. So no mpirun necessary.\"\n\n";
776 // out << "\techo\necho\n";
777 // return;
778 // }
779 //
780 // out << "\techo \"" << ss.str() << "\""; //print mpirun
781 // out << "\t\n\techo\n\techo\n\n";
782 // out << ssUID.str() << "\n\n";
783 // out << ss.str(); //run mpirun
784 //
785 // out << "\n\n";
786 // //out << ""\tif [ ${ret:-1} -eq 0 ]; then\n\t\texit\n\tfi\n";
787 // //out << "\ndone\n";
788 //}
789 //
790 //
792 // void XDAQContextTable::outputAppPriority(std::ostream &out, const std::string&
793 // stateMachineCommand)
794 //{
795 // //output app ID and priority order [1:255] pairs.. new line separated
796 // // 0/undefined gets translated to 100
797 //
798 // for (XDAQContext &context : contexts_)
799 // for (XDAQApplication &app : context.applications_)
800 // {
801 // out << app.id_ << "\n";
802 //
803 // if(app.stateMachineCommandPriority_.find(stateMachineCommand) ==
804 // app.stateMachineCommandPriority_.end()) out << 100; else
805 // out << ((app.stateMachineCommandPriority_[stateMachineCommand])?
806 // app.stateMachineCommandPriority_[stateMachineCommand]:100);
807 //
808 // out << "\n";
809 // }
810 //}
811 
812 //========================================================================================================================
813 void XDAQContextTable::outputXDAQXML(std::ostream& out)
814 {
815  // each generated context will look something like this:
816  //<xc:Context id="0" url="http://${SUPERVISOR_SERVER}:${PORT}">
820  //</xc:Context>
821 
822  // print xml header information and declare xc partition
823  out << "<?xml version='1.0'?>\n"
824  << "<xc:Partition \txmlns:xsi\t= \"http://www.w3.org/2001/XMLSchema-instance\"\n"
825  << "\t\txmlns:soapenc\t= \"http://schemas.xmlsoap.org/soap/encoding/\"\n"
826  << "\t\txmlns:xc\t= "
827  "\"http://xdaq.web.cern.ch/xdaq/xsd/2004/XMLConfiguration-30\">\n\n";
828 
829  // print partition open
830  // for each context
831  // open context
832  // for each app in context
833  // print application
834  // print module
835  // close context
836  // close partition
837 
838  char tmp[200];
839  for(XDAQContext& context : contexts_)
840  {
841  //__COUT__ << context.contextUID_ << __E__;
842 
843  sprintf(tmp,
844  "\t<!-- ContextUID='%s' sourceConfig='%s' -->",
845  context.contextUID_.c_str(),
846  context.sourceConfig_.c_str());
847  out << tmp << "\n";
848 
849  if(!context.status_) // comment out if disabled
850  out << "\t<!--\n";
851 
852  sprintf(tmp,
853  "\t<xc:Context id=\"%u\" url=\"%s:%u\">",
854  context.id_,
855  context.address_.c_str(),
856  context.port_);
857  out << tmp << "\n\n";
858 
859  for(XDAQApplication& app : context.applications_)
860  {
861  //__COUT__ << app.id_ << __E__;
862 
863  if(context.status_)
864  {
865  sprintf(
866  tmp,
867  "\t\t<!-- Application GroupID = '%s' UID='%s' sourceConfig='%s' -->",
868  app.applicationGroupID_.c_str(),
869  app.applicationUID_.c_str(),
870  app.sourceConfig_.c_str());
871  out << tmp << "\n";
872 
873  if(!app.status_) // comment out if disabled
874  out << "\t\t<!--\n";
875  }
876 
877  sprintf(tmp,
878  "\t\t<xc:Application class=\"%s\" id=\"%u\" instance=\"%u\" "
879  "network=\"%s\" group=\"%s\">\n",
880  app.class_.c_str(),
881  app.id_,
882  app.instance_,
883  app.network_.c_str(),
884  app.group_.c_str());
885  out << tmp;
886 
888  int foundColon = app.class_.rfind(':');
889  if(foundColon >= 0)
890  ++foundColon;
891  else
892  {
893  __SS__ << "Illegal XDAQApplication class name value of '" << app.class_
894  << "' - please check the entry for app ID = " << app.id_ << __E__;
895  __SS_THROW__;
896  }
897  out << "\t\t\t<properties xmlns=\"urn:xdaq-application:"
898  << app.class_.substr(foundColon) << "\" xsi:type=\"soapenc:Struct\">\n";
899 
900  //__COUT__ << "app.properties_ " << app.properties_.size() << __E__;
901  for(XDAQApplicationProperty& appProperty : app.properties_)
902  {
903  if(appProperty.type_ == "ots::SupervisorProperty")
904  continue; // skip ots Property values
905 
906  if(!appProperty.status_)
907  out << "\t\t\t\t<!--\n";
908 
909  sprintf(tmp,
910  "\t\t\t\t<%s xsi:type=\"%s\">%s</%s>\n",
911  appProperty.name_.c_str(),
912  appProperty.type_.c_str(),
913  appProperty.value_.c_str(),
914  appProperty.name_.c_str());
915  out << tmp;
916 
917  if(!appProperty.status_)
918  out << "\t\t\t\t-->\n";
919  }
920  out << "\t\t\t</properties>\n";
922 
923  out << "\t\t</xc:Application>\n";
924 
925  sprintf(tmp, "\t\t<xc:Module>%s</xc:Module>\n", app.module_.c_str());
926  out << tmp;
927 
928  if(context.status_ && !app.status_)
929  out << "\t\t-->\n";
930  out << "\n";
931 
932  // __COUT__ << "DONE" << __E__;
933  }
934 
935  out << "\t</xc:Context>\n";
936  if(!context.status_)
937  out << "\t-->\n";
938  out << "\n";
939  }
940 
941  //__COUT__ << "DONE" << __E__;
942  out << "</xc:Partition>\n\n\n";
943 }
944 
945 //========================================================================================================================
946 std::string XDAQContextTable::getContextUID(const std::string& url) const
947 {
948  for(auto context : contexts_)
949  {
950  if(!context.status_)
951  continue;
952 
953  if(url == context.address_ + ":" + std::to_string(context.port_))
954  return context.contextUID_;
955  }
956  return "";
957 }
958 
959 //========================================================================================================================
960 std::string XDAQContextTable::getApplicationUID(const std::string& url,
961  unsigned int id) const
962 {
963  //__COUTV__(url); __COUTV__(id);
964  for(auto context : contexts_)
965  {
966  //__COUT__ << "Checking " << (context.address_ + ":" +
967  // std::to_string(context.port_)) << __E__;
968  //__COUTV__(context.status_);
969 
970  if(!context.status_)
971  continue;
972 
973  //__COUT__ << "Checking " << (context.address_ + ":" +
974  // std::to_string(context.port_)) << __E__;
975  if(url == context.address_ + ":" + std::to_string(context.port_))
976  for(auto application : context.applications_)
977  {
978  //__COUTV__(application.status_); __COUTV__(application.id_);
979  if(!application.status_)
980  continue;
981 
982  if(application.id_ == id)
983  {
984  return application.applicationUID_;
985  }
986  }
987  }
988  return "";
989 }
990 
991 DEFINE_OTS_TABLE(XDAQContextTable)
void outputXDAQXML(std::ostream &out)