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