otsdaq  v2_00_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 NO app id repeats
343  if(appIdSet.find(contexts_.back().applications_.back().id_) != appIdSet.end())
344  {
345  __SS__ << "XDAQ Application IDs are not unique. Specifically at id=" <<
346  contexts_.back().applications_.back().id_ << " appName=" <<
347  contexts_.back().applications_.back().applicationUID_ << std::endl;
348  __COUT_ERR__ << "\n" << ss.str();
349  throw std::runtime_error(ss.str());
350  }
351 
352  //assert Gateway is 200
353  if((contexts_.back().applications_.back().id_ == 200 &&
354  contexts_.back().applications_.back().class_ != XDAQContextConfiguration::GATEWAY_SUPERVISOR_CLASS &&
355  contexts_.back().applications_.back().class_ != XDAQContextConfiguration::DEPRECATED_SUPERVISOR_CLASS) ||
356  (contexts_.back().applications_.back().id_ != 200 &&
357  (contexts_.back().applications_.back().class_ == XDAQContextConfiguration::GATEWAY_SUPERVISOR_CLASS ||
358  contexts_.back().applications_.back().class_ == XDAQContextConfiguration::DEPRECATED_SUPERVISOR_CLASS)))
359  {
360  __SS__ << "XDAQ Application ID of 200 is reserved for the Gateway Supervisor " <<
361  XDAQContextConfiguration::GATEWAY_SUPERVISOR_CLASS << ". Conflict specifically at id=" <<
362  contexts_.back().applications_.back().id_ << " appName=" <<
363  contexts_.back().applications_.back().applicationUID_ << std::endl;
364  __SS_THROW__;
365  }
366 
367  appIdSet.insert(contexts_.back().applications_.back().id_);
368 
369  //convert defaults to values
370  if (appChild.second.getNode(colApplication_.colInstance_).isDefaultValue())
371  contexts_.back().applications_.back().instance_ = 1;
372  else
373  appChild.second.getNode(colApplication_.colInstance_).getValue(contexts_.back().applications_.back().instance_);
374 
375  if (appChild.second.getNode(colApplication_.colNetwork_).isDefaultValue())
376  contexts_.back().applications_.back().network_ = "local";
377  else
378  appChild.second.getNode(colApplication_.colNetwork_).getValue(contexts_.back().applications_.back().network_);
379 
380  if (appChild.second.getNode(colApplication_.colGroup_).isDefaultValue())
381  contexts_.back().applications_.back().group_ = "daq";
382  else
383  appChild.second.getNode(colApplication_.colGroup_).getValue(contexts_.back().applications_.back().group_);
384 
385  appChild.second.getNode(colApplication_.colModule_).getValue(contexts_.back().applications_.back().module_);
386 
387  try
388  {
389  appChild.second.getNode(colApplication_.colConfigurePriority_).getValue(contexts_.back().applications_.back().stateMachineCommandPriority_["Configure"]);
390  appChild.second.getNode(colApplication_.colStartPriority_).getValue(contexts_.back().applications_.back().stateMachineCommandPriority_["Start"]);
391  appChild.second.getNode(colApplication_.colStopPriority_).getValue(contexts_.back().applications_.back().stateMachineCommandPriority_["Stop"]);
392  }
393  catch(...)
394  {
395  __COUT__ << "Ignoring missing state machine priorities..." << __E__;
396  }
397 
398 
399  auto appPropertyLink = appChild.second.getNode(colApplication_.colLinkToPropertyConfiguration_);
400  if (!appPropertyLink.isDisconnected())
401  {
402  //add xdaq application properties to this context
403 
404  auto appPropertyChildren = appPropertyLink.getChildren();
405 
406  //__COUT__ << "appPropertyChildren.size() " << appPropertyChildren.size() << std::endl;
407 
408  for (auto appPropertyChild : appPropertyChildren)
409  {
410  contexts_.back().applications_.back().properties_.push_back(XDAQApplicationProperty());
411  contexts_.back().applications_.back().properties_.back().status_ =
412  appPropertyChild.second.getNode(colAppProperty_.colStatus_).getValue<bool>();
413  contexts_.back().applications_.back().properties_.back().name_ =
414  appPropertyChild.second.getNode(colAppProperty_.colPropertyName_).getValue<std::string>();
415  contexts_.back().applications_.back().properties_.back().type_ =
416  appPropertyChild.second.getNode(colAppProperty_.colPropertyType_).getValue<std::string>();
417  contexts_.back().applications_.back().properties_.back().value_ =
418  appPropertyChild.second.getNode(colAppProperty_.colPropertyValue_).getValue<std::string>();
419 
420  //__COUT__ << contexts_.back().applications_.back().properties_.back().name_ << std::endl;
421  }
422  }
423  //else
424  // __COUT__ << "Disconnected." << std::endl;
425  }
426 
427  //check artdaq type
428  if (isARTDAQContext(contexts_.back().contextUID_))
429  {
430  //artdaqContexts_.push_back(contexts_.size() - 1);
431 
432  if (contexts_.back().applications_.size() != 1)
433  {
434  __SS__ << "ARTDAQ Context '" << contexts_.back().contextUID_ <<
435  "' must have one Application! " <<
436  contexts_.back().applications_.size() << " were found. " << std::endl;
437  throw std::runtime_error(ss.str());
438  }
439 
440  if (!contexts_.back().status_) continue; //skip if disabled
441 
442  if (contexts_.back().applications_[0].class_ == //if board reader
443  "ots::ARTDAQDataManagerSupervisor")
444  artdaqBoardReaders_.push_back(contexts_.size() - 1);
445  else if (contexts_.back().applications_[0].class_ == //if event builder
446  "ots::EventBuilderApp")
447  artdaqEventBuilders_.push_back(contexts_.size() - 1);
448  else if (contexts_.back().applications_[0].class_ == //if aggregator
449  "ots::DataLoggerApp" ||
450  contexts_.back().applications_[0].class_ == //if aggregator
451  "ots::DispatcherApp")
452  artdaqAggregators_.push_back(contexts_.size() - 1);
453  else
454  {
455  __SS__ << "ARTDAQ Context must be have Application of an allowed class type:\n " <<
456  "\tots::ARTDAQDataManagerSupervisor\n" <<
457  "\tots::EventBuilderApp\n" <<
458  "\tots::DataLoggerApp\n" <<
459  "\tots::DispatcherApp\n" <<
460  "\nClass found was " <<
461  contexts_.back().applications_[0].class_ << std::endl;
462  throw std::runtime_error(ss.str());
463  }
464 
465  }
466 
467  }
468 }
469 
470 //========================================================================================================================
471 //void XDAQContextConfiguration::outputXDAQScript(std::ostream &out)
472 //{
473  /*
474  the file will look something like this:
475  #!/bin/sh
476 
477  echo
478  echo
479 
480  echo "Launching XDAQ contexts..."
481 
482  #for each XDAQ context
483  xdaq.exe -p ${CONTEXT_PORT} -e ${XDAQ_ARGS} &
484 
485  */
486 
487  // out << "#!/bin/sh\n\n";
488  //
489  // out << "echo\necho\n\n";
490  //
491  // out << "echo \"Launching XDAQ contexts...\"\n\n";
492  // out << "#for each XDAQ context\n";
493  //
494  //
495  // std::stringstream ss;
496  // int count = 0;
497  // //for each non-"ART" or "ARTDAQ" context make a xdaq entry
498  // for(XDAQContext &context:contexts_)
499  // {
500  // if(isARTDAQContext(context.contextUID_))
501  // continue; //skip if UID does identify as artdaq
502  //
503  // if(!context.status_)
504  // continue; //skip if disabled
505  //
506  // //at this point we have a xdaq context.. so make an xdaq entry
507  //
508  // ++count;
509  // ss << "echo \"xdaq.exe -p " <<
510  // context.port_ << " -e ${XDAQ_ARGS} &\"\n";
511  // ss << "xdaq.exe -p " <<
512  // context.port_ << " -e ${XDAQ_ARGS} & " <<
513  // "#" << context.contextUID_ << "\n";
514  // }
515  //
516  //
517  // if(count == 0) //if no artdaq contexts at all
518  // {
519  // out << "echo \"No XDAQ (non-artdaq) contexts found.\"\n\n";
520  // out << "echo\necho\n";
521  // return;
522  // }
523  //
524  // out << ss.str();
525  //
526  // out << "\n\n";
527  //}
528 
530  //void XDAQContextConfiguration::outputARTDAQScript(std::ostream &out)
531  //{
532  /*
533  the file will look something like this:
534  #!/bin/sh
535 
536 
537  echo
538  echo
539  while [ 1 ]; do
540 
541  echo "Cleaning up old MPI instance..."
542  killall mpirun
543 
544 
545  echo "Starting mpi run..."
546  echo "$1"
547  echo
548  echo
549 
550  echo mpirun $1 \
551  -np 1 xdaq.exe -p ${ARTDAQ_BOARDREADER_PORT1} -e ${XDAQ_ARGS} : \
552  -np 1 xdaq.exe -p ${ARTDAQ_BOARDREADER_PORT2} -e ${XDAQ_ARGS} : \
553  -np 1 xdaq.exe -p ${ARTDAQ_BUILDER_PORT} -e ${XDAQ_ARGS} : \
554  -np 1 xdaq.exe -p ${ARTDAQ_AGGREGATOR_PORT} -e ${XDAQ_ARGS} &
555 
556  echo
557  echo
558 
559  ret=mpirun $1 \
560  -np 1 xdaq.exe -p ${ARTDAQ_BOARDREADER_PORT1} -e ${XDAQ_ARGS} : \
561  -np 1 xdaq.exe -p ${ARTDAQ_BOARDREADER_PORT2} -e ${XDAQ_ARGS} : \
562  -np 1 xdaq.exe -p ${ARTDAQ_BUILDER_PORT} -e ${XDAQ_ARGS} : \
563  -np 1 xdaq.exe -p ${ARTDAQ_AGGREGATOR_PORT} -e ${XDAQ_ARGS}
564 
565  if [ $ret -eq 0 ]; then
566  exit
567  fi
568 
569  done
570  */
571 
572  // __COUT__ << artdaqContexts_.size() << " total artdaq context(s)." << std::endl;
573  // __COUT__ << artdaqBoardReaders_.size() << " active artdaq board reader(s)." << std::endl;
574  // __COUT__ << artdaqEventBuilders_.size() << " active artdaq event builder(s)." << std::endl;
575  // __COUT__ << artdaqAggregators_.size() << " active artdaq aggregator(s)." << std::endl;
576  //
577  // out << "#!/bin/sh\n\n";
578  //
579  // out << "\techo\n\techo\n\n";
580  // //out << "while [ 1 ]; do\n\n";
581  //
582  // //out << "\techo \"Cleaning up old MPI instance...\"\n";
583  //
584  // out << "\techo \"" <<
585  // artdaqContexts_.size() << " artdaq Contexts." <<
586  // "\"\n";
587  // out << "\techo \"\t" <<
588  // artdaqBoardReaders_.size() << " artdaq board readers." <<
589  // "\"\n";
590  // out << "\techo \"\t" <<
591  // artdaqEventBuilders_.size() << " artdaq event builders." <<
592  // "\"\n";
593  // out << "\techo \"\t" <<
594  // artdaqAggregators_.size() << " artdaq aggregators_." <<
595  // "\"\n";
596  //
597  // //out << "\tkillall mpirun\n";
598  // out << "\techo\n\techo\n\n";
599  //
600  // out << "\techo \"Starting mpi run...\"\n";
601  // out << "\techo \"$1\"\n\techo\n\techo\n\n";
602  //
603  //
604  //
605  // std::stringstream ss,ssUID;
606  // int count = 0;
607  //
608  // //ss << "\tret=`mpirun $1 \\\n"; `
609  //
610  // ss << "\tmpirun $1 \\\n";
611  //
612  // //for each "ART" or "ARTDAQ" context make an mpi entry
613  // //make an mpi entry for board readers, then event builders, then aggregators
614  //
615  // for(auto &i:artdaqBoardReaders_)
616  // {
617  // if(count++) //add line breaks if not first context
618  // ss << ": \\\n";
619  //
620  // ss << " -np 1 xdaq.exe -p " <<
621  // contexts_[i].port_ << " -e ${XDAQ_ARGS} ";
622  //
623  // ssUID << "\n\t#board reader \t context.port_ \t " << contexts_[i].port_ <<
624  // ": \t" << contexts_[i].contextUID_;
625  // }
626  //
627  // for(auto &i:artdaqEventBuilders_)
628  // {
629  // if(count++) //add line breaks if not first context
630  // ss << ": \\\n";
631  //
632  // ss << " -np 1 xdaq.exe -p " <<
633  // contexts_[i].port_ << " -e ${XDAQ_ARGS} ";
634  //
635  // ssUID << "\n\t#event builder \t context.port_ \t " << contexts_[i].port_ <<
636  // ": \t" << contexts_[i].contextUID_;
637  // }
638  //
639  // for(auto &i:artdaqAggregators_)
640  // {
641  // if(count++) //add line breaks if not first context
642  // ss << ": \\\n";
643  //
644  // ss << " -np 1 xdaq.exe -p " <<
645  // contexts_[i].port_ << " -e ${XDAQ_ARGS} ";
646  //
647  // ssUID << "\n\t#aggregator \t context.port_ \t " << contexts_[i].port_ <<
648  // ": \t" << contexts_[i].contextUID_;
649  // }
650  //
651  //
652  // if(count == 0) //if no artdaq contexts at all
653  // {
654  // out << "\techo \"No ARTDAQ contexts found. So no mpirun necessary.\"\n\n";
655  // out << "\techo\necho\n";
656  // return;
657  // }
658  //
659  // out << "\techo \"" << ss.str() << "\""; //print mpirun
660  // out << "\t\n\techo\n\techo\n\n";
661  // out << ssUID.str() << "\n\n";
662  // out << ss.str(); //run mpirun
663  //
664  // out << "\n\n";
665  // //out << ""\tif [ ${ret:-1} -eq 0 ]; then\n\t\texit\n\tfi\n";
666  // //out << "\ndone\n";
667  //}
668  //
669 //
671 //void XDAQContextConfiguration::outputAppPriority(std::ostream &out, const std::string& stateMachineCommand)
672 //{
673 // //output app ID and priority order [1:255] pairs.. new line separated
674 // // 0/undefined gets translated to 100
675 //
676 // for (XDAQContext &context : contexts_)
677 // for (XDAQApplication &app : context.applications_)
678 // {
679 // out << app.id_ << "\n";
680 //
681 // if(app.stateMachineCommandPriority_.find(stateMachineCommand) == app.stateMachineCommandPriority_.end())
682 // out << 100;
683 // else
684 // out << ((app.stateMachineCommandPriority_[stateMachineCommand])?
685 // app.stateMachineCommandPriority_[stateMachineCommand]:100);
686 //
687 // out << "\n";
688 // }
689 //}
690 
691 //========================================================================================================================
692 void XDAQContextConfiguration::outputXDAQXML(std::ostream &out)
693 {
694  //each generated context will look something like this:
695  //<xc:Context id="0" url="http://${SUPERVISOR_SERVER}:${PORT}">
698  //</xc:Context>
699 
700  //print xml header information and declare xc partition
701  out << "<?xml version='1.0'?>\n" <<
702  "<xc:Partition \txmlns:xsi\t= \"http://www.w3.org/2001/XMLSchema-instance\"\n" <<
703  "\t\txmlns:soapenc\t= \"http://schemas.xmlsoap.org/soap/encoding/\"\n" <<
704  "\t\txmlns:xc\t= \"http://xdaq.web.cern.ch/xdaq/xsd/2004/XMLConfiguration-30\">\n\n";
705 
706  //print partition open
707  //for each context
708  // open context
709  // for each app in context
710  // print application
711  // print module
712  // close context
713  //close partition
714 
715  char tmp[200];
716  for (XDAQContext &context : contexts_)
717  {
718 
719  //__COUT__ << context.contextUID_ << std::endl;
720 
721  sprintf(tmp, "\t<!-- ContextUID='%s' sourceConfig='%s' -->",
722  context.contextUID_.c_str(), context.sourceConfig_.c_str());
723  out << tmp << "\n";
724 
725  if (!context.status_) //comment out if disabled
726  out << "\t<!--\n";
727 
728  sprintf(tmp, "\t<xc:Context id=\"%u\" url=\"%s:%u\">", context.id_, context.address_.c_str(), context.port_);
729  out << tmp << "\n\n";
730 
731  for (XDAQApplication &app : context.applications_)
732  {
733  //__COUT__ << app.id_ << std::endl;
734 
735 
736  if (context.status_)
737  {
738  sprintf(tmp, "\t\t<!-- Application GroupID = '%s' UID='%s' sourceConfig='%s' -->",
739  app.applicationGroupID_.c_str(), app.applicationUID_.c_str(), app.sourceConfig_.c_str());
740  out << tmp << "\n";
741 
742  if (!app.status_) //comment out if disabled
743  out << "\t\t<!--\n";
744  }
745 
746  sprintf(tmp, "\t\t<xc:Application class=\"%s\" id=\"%u\" instance=\"%u\" network=\"%s\" group=\"%s\">\n",
747  app.class_.c_str(), app.id_, app.instance_, app.network_.c_str(), app.group_.c_str());
748  out << tmp;
749 
751  int foundColon = app.class_.rfind(':');
752  if (foundColon >= 0) ++foundColon;
753  else
754  {
755  __SS__ << "Illegal XDAQApplication class name value of '" << app.class_
756  << "' - please check the entry for app ID = " << app.id_ << __E__;
757  throw std::runtime_error(ss.str());
758  }
759  out << "\t\t\t<properties xmlns=\"urn:xdaq-application:" <<
760  app.class_.substr(foundColon) <<
761  "\" xsi:type=\"soapenc:Struct\">\n";
762 
763  //__COUT__ << "app.properties_ " << app.properties_.size() << std::endl;
764  for (XDAQApplicationProperty &appProperty : app.properties_)
765  {
766 
767  if (appProperty.type_ == "ots-only Property") continue; //skip otsProperty values
768 
769  if (!appProperty.status_)
770  out << "\t\t\t\t<!--\n";
771 
772  sprintf(tmp, "\t\t\t\t<%s xsi:type=\"%s\">%s</%s>\n",
773  appProperty.name_.c_str(),
774  appProperty.type_.c_str(),
775  appProperty.value_.c_str(),
776  appProperty.name_.c_str());
777  out << tmp;
778 
779  if (!appProperty.status_)
780  out << "\t\t\t\t-->\n";
781  }
782  out << "\t\t\t</properties>\n";
784 
785  out << "\t\t</xc:Application>\n";
786 
787 
788  sprintf(tmp, "\t\t<xc:Module>%s</xc:Module>\n", app.module_.c_str());
789  out << tmp;
790 
791  if (context.status_ && !app.status_)
792  out << "\t\t-->\n";
793  out << "\n";
794 
795  // __COUT__ << "DONE" << __E__;
796  }
797 
798  out << "\t</xc:Context>\n";
799  if (!context.status_)
800  out << "\t-->\n";
801  out << "\n";
802  }
803 
804  //__COUT__ << "DONE" << __E__;
805  out << "</xc:Partition>\n\n\n";
806 
807 }
808 
809 //========================================================================================================================
810 std::string XDAQContextConfiguration::getContextUID(const std::string &url) const
811 {
812  for (auto context : contexts_)
813  {
814  if (!context.status_) continue;
815 
816  if (url == context.address_ + ":" + std::to_string(context.port_))
817  return context.contextUID_;
818  }
819  return "";
820 }
821 
822 //========================================================================================================================
823 std::string XDAQContextConfiguration::getApplicationUID(const std::string &url, unsigned int id) const
824 {
825  for (auto context : contexts_)
826  {
827  if (!context.status_) continue;
828 
829  if (url == context.address_ + ":" + std::to_string(context.port_))
830  for (auto application : context.applications_)
831  {
832  if (!application.status_) continue;
833 
834  if (application.id_ == id)
835  {
836  return application.applicationUID_;
837  }
838  }
839  }
840  return "";
841 }
842 
843 DEFINE_OTS_CONFIGURATION(XDAQContextConfiguration)