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