otsdaq-utilities  3.10.00
VisualSupervisor.cc
1 #include "otsdaq-utilities/Visualization/VisualSupervisor.h"
2 #include "otsdaq/DataManager/DataManagerSingleton.h"
3 #include "otsdaq/Macros/BinaryStringMacros.h"
4 #include "otsdaq/RootUtilities/VisualDataManager.h"
5 #include "otsdaq/XmlUtilities/XmlDocument.h"
6 // #include "otsdaq/otsdaq/Macros/MessageTools.h"
7 #include <boost/regex.hpp>
8 #include "otsdaq/DataManager/DQMHistosConsumerBase.h"
9 #include "otsdaq/Macros/MessageTools.h"
10 #include "otsdaq/RootUtilities/RootFileExplorer.h"
11 
15 #include <TBranchElement.h>
16 #include <TBuffer.h>
17 #include <TBufferJSON.h>
18 #include <TCanvas.h>
19 #include <TClass.h>
20 #include <TDirectory.h>
21 #include <TFile.h>
22 #include <TH1.h>
23 #include <TH2.h>
24 #include <TIterator.h>
25 #include <TKey.h>
26 #include <TProfile.h>
27 #include <TROOT.h>
28 #include <TRegexp.h>
29 #include <TString.h>
30 #include <TTree.h>
31 #include "TBufferFile.h"
32 #include "TObject.h"
33 
34 #include <dirent.h> /*DIR and dirent*/
35 #include <sys/stat.h> /*mkdir*/
36 
37 #include <xdaq/NamespaceURI.h>
38 
39 #include <chrono>
40 #include <fstream>
41 #include <iostream>
42 #include <map>
43 #include <memory>
44 #include <mutex>
45 
46 #include "otsdaq/DataManager/DataConsumer.h"
47 #include "otsdaq/DataManager/DataProducerBase.h"
48 
49 // #include <thread>
50 
51 #define ROOT_BROWSER_PATH __ENV__("ROOT_BROWSER_PATH")
52 #define ROOT_DISPLAY_CONFIG_PATH __ENV__("ROOT_DISPLAY_CONFIG_PATH")
53 
54 #define LIVEDQM_DIR std::string("LIVE_DQM")
55 // Top-level directory the DQM consumer books everything under (see
56 // DQMMu2eHistoConsumer::startProcessingData). Hidden from the browser: a live path
57 // without it is mapped onto it, a path that already names it passes through.
58 #define LIVE_TOP_DIR std::string("Mu2eHistos")
59 #define PRE_MADE_ROOT_CFG_DIR std::string("Pre-made Views")
60 #define HISTORY_DIR std::string("History")
61 
62 #define PRE_MADE_ROOT_CFG_FILE_EXT std::string(".rcfg")
63 
64 #define PREFERENCES_PATH std::string(__ENV__("SERVICE_DATA_PATH")) + "/VisualizerData/"
65 #define PREFERENCES_FILE_EXT ".pref"
66 
67 #define ROOT_VIEWER_PERMISSIONS_THRESHOLD 100
68 
69 using namespace ots;
70 
71 #undef __MF_SUBJECT__
72 #define __MF_SUBJECT__ "Visualizer"
73 
74 XDAQ_INSTANTIATOR_IMPL(VisualSupervisor)
75 
76 #undef STDLINE
77 #define STDLINE(X, Y) __COUT__ << X
78 
79 //==============================================================================
80 VisualSupervisor::VisualSupervisor(xdaq::ApplicationStub* stub)
81  : CoreSupervisorBase(stub), theDataManager_(nullptr), loadedRunNumber_(-1)
82 {
83  __SUP_COUT__ << "Constructor." << __E__;
84  INIT_MF("VisualSupervisor");
85 
86  mkdir(((std::string)PREFERENCES_PATH).c_str(), 0755);
87  ROOT::EnableThreadSafety();
88 
89  __SUP_COUT__ << "Constructed." << __E__;
90 } // end constructor
91 
92 //========================================================================================================================
93 VisualSupervisor::~VisualSupervisor(void)
94 {
95  __SUP_COUT__ << "Destructor." << __E__;
96  destroy();
97  __SUP_COUT__ << "Destructed." << __E__;
98 } // end destructor
99 
100 //========================================================================================================================
101 void VisualSupervisor::destroy(void)
102 {
103  __SUP_COUT__ << "Destroying..." << __E__;
104 
105  DataManagerSingleton::deleteInstance(CorePropertySupervisorBase::getSupervisorUID());
106  if(theStateMachineImplementation_.size() > 1)
107  {
108  __SS__ << "Not expecting more than one visual data manager!" << __E__;
109  __SS_THROW__;
110  }
111  if(theStateMachineImplementation_.size())
112  theStateMachineImplementation_.pop_back();
113  else
114  __COUT_WARN__ << "No visual data manager was pushed." << __E__;
115 } // end destroy()
116 
117 //==============================================================================
118 void VisualSupervisor::transitionConfiguring(toolbox::Event::Reference /*e*/)
119 try
120 {
121  __SUP_COUT__ << "Configuring..." << __E__;
122 
123  CoreSupervisorBase::configureInit();
124 
125  try
126  {
127  ConfigurationTree testAppLink = theConfigurationManager_->getNode(
128  "/" +
129  theConfigurationManager_->__GET_CONFIG__(XDAQContextTable)->getTableName() +
130  CorePropertySupervisorBase::getSupervisorConfigurationPath());
131  }
132  catch(const std::runtime_error& e)
133  {
134  __SS__ << "The link to the Visual Supervisor configuration seems to be broken. "
135  "Please check this path: "
136  << "/" +
137  theConfigurationManager_->__GET_CONFIG__(XDAQContextTable)
138  ->getTableName() +
139  CorePropertySupervisorBase::getSupervisorConfigurationPath()
140  << __E__ << __E__ << e.what() << __E__;
141  __SS_THROW__;
142  }
143 
144  ConfigurationTree appLink = theConfigurationManager_->getNode(
145  "/" + theConfigurationManager_->__GET_CONFIG__(XDAQContextTable)->getTableName() +
146  CorePropertySupervisorBase::getSupervisorConfigurationPath());
147 
148  __COUTV__(appLink.getValueAsString());
149 
150  if(!appLink.isDisconnected())
151  {
152  theDataManager_ = DataManagerSingleton::getInstance<VisualDataManager>(
153  theConfigurationManager_->getNode(
154  theConfigurationManager_->__GET_CONFIG__(XDAQContextTable)
155  ->getTableName()),
156  CorePropertySupervisorBase::getSupervisorConfigurationPath(),
157  CorePropertySupervisorBase::getSupervisorUID());
158 
159  CoreSupervisorBase::theStateMachineImplementation_.push_back(theDataManager_);
160 
161  __SUP_COUT__ << "Done instantiating Visual data manager." << __E__;
162  }
163  else
164  __SUP_COUT__ << "No Visual Supervisor configuration link, so skipping Visual "
165  "data manager instantiation."
166  << __E__;
167 
168  // just handle FSMs
169  CoreSupervisorBase::transitionConfiguringFSMs();
170 
171  __SUP_COUT__ << "Configured." << __E__;
172 } // end transitionConfiguring()
173 catch(const std::runtime_error& e)
174 {
175  __SS__ << "Error with VisualSupervisor::transitionConfiguring(): " << e.what()
176  << __E__;
177  __COUT_ERR__ << ss.str();
178  // ExceptionHandler(ExceptionHandlerRethrow::no, ss.str());
179 
180  //__SS_THROW_ONLY__;
181  theStateMachine_.setErrorMessage(ss.str());
182  throw toolbox::fsm::exception::Exception(
183  "Transition Error" /*name*/,
184  ss.str() /* message*/,
185  "VisualSupervisor::transitionConfiguring" /*module*/,
186  __LINE__ /*line*/,
187  __FUNCTION__ /*function*/
188  );
189 } // end transitionConfiguring() catch
190 
191 //==============================================================================
192 void VisualSupervisor::transitionHalting(toolbox::Event::Reference e)
193 {
194  __SUP_COUT__ << "Halting..." << __E__;
195 
197  destroy();
198 
199  __SUP_COUT__ << "Halted." << __E__;
200 } // end transitionHalting()
201 
202 //==============================================================================
207 {
208  CorePropertySupervisorBase::setSupervisorProperty(
209  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AllowNoLoginRequestTypes,
210  "setUserPreferences | getUserPreferences | getDirectoryContents | getRoot | "
211  "getEvents | getDataStatus");
212 
213  CorePropertySupervisorBase::setSupervisorProperty(
214  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserPermissionsThreshold,
215  "*=1 | rootAdminControls=100");
216 } //end setSupervisorPropertyDefaults()
217 
218 //========================================================================================================================
222 {
223  CorePropertySupervisorBase::setSupervisorProperty(
224  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes,
225  "getRoot | getEvents | getDataStatus");
226  CorePropertySupervisorBase::setSupervisorProperty(
227  CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NoXmlWhiteSpaceRequestTypes,
228  "getRoot | getEvents | getDataStatus");
229  //Note: json data in ROOTJS library expects no funny characters
230 } //end forceSupervisorPropertyValues()
231 
232 //========================================================================================================================
233 void VisualSupervisor::request(const std::string& requestType,
234  cgicc::Cgicc& cgiIn,
235  HttpXmlDocument& xmlOut,
236  const WebUsers::RequestUserInfo& userInfo)
237 {
238  // Commands
239  // getRawData
240  // getGeometry
241  // getEvents
242  // getRoot
243  // getDirectoryContents
244  // setUserPreferences
245  // getUserPreference
246 
247  // if (requestType == "getHisto" && theDataManager_->getLiveDQMHistos() != 0)
248  // {
249  // // TH1I* histo =
250  // (TH1I*)theDataManager_->getLiveDQMHistos()->get("Planes/Plane_0_Occupancy");
251  //
252  // // theDataManager_->load("Run185_Histo.root","Histograms");
253  // //TH1F* histo1d = theDataManager_->getFileDQMHistos().getHisto1D();
254  // //TCanvas* canvas = theDataManager_->getFileDQMHistos().getCanvas ();
255  // //TH2F* histo2d = theDataManager_->getFileDQMHistos().getHisto2D();
256  // //TProfile* profile = theDataManager_->getFileDQMHistos().getProfile();
257  //
258  // }
259  // std::stringstream ss;
260  // ss << "Request type: |" << requestType << "|";
261  // STDLINE(ss.str(),"") ;
262 
263  __SUP_COUT__ << "Request type: " << requestType << __E__;
264  if(requestType ==
265  "getRawData") // ################################################################################################################
266  {
267  __SUP_COUT__ << __E__;
268  try
269  {
270  // TODO -- add timestamp, so we know if data is new
271 
272  if(theDataManager_ == nullptr)
273  {
274  __SS__ << "No data manager instantiated." << __E__;
275  __SS_THROW__;
276  }
277  __SUP_COUT__ << "Getting Raw data and converting to binary string" << __E__;
278  // xmlOut.addBinaryStringToData("rawData",
279  // theDataManager_->getRawData());
280  __SUP_COUT__ << __E__;
281  __SUP_SS__ << "Raw data visualizion is deprecated!" << __E__;
282  __SUP_SS_THROW__;
283  }
284  catch(std::exception const& e)
285  {
286  __SUP_COUT__
287  << "ERROR! Exception while getting raw data. Incoming exception data..."
288  << __E__;
289  __SUP_COUT__ << e.what() << __E__;
290  __SUP_COUT__ << "End Exception Data" << __E__;
291  }
292  catch(...)
293  {
294  __SUP_COUT__ << "ERROR! Something went wrong trying to get raw data."
295  << __E__;
296  try
297  {
298  throw;
299  } //one more try to printout extra info
300  catch(const std::exception& e)
301  {
302  __SUP_COUT_ERR__ << "Exception message: " << e.what();
303  }
304  catch(...)
305  {
306  }
307  __SUP_COUT_INFO__ << "ERROR! Something went wrong trying to get raw data."
308  << __E__;
309  }
310  }
311  else if(
312  requestType ==
313  "getDataStatus") // ################################################################################################################
314  {
315  // Throughput snapshot of the live-DQM data path, for the viewer status strip.
316  // One <processor> per producer/consumer with cumulative counters; the browser
317  // keeps the previous sample and turns deltas into rates. Cumulative counters
318  // mean a missed poll loses nothing.
319  //
320  // <processor name= role=producer|consumer buffer= packets= bytes= errors=
321  // busyNanos= queued= capacity= [clients= socketBacklogBytes=]/>
322  // <serverTime value=ms since epoch/>
323  // <ready value=0|1/>
324  xmlOut.addTextElementToData(
325  "serverTime",
326  std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
327  std::chrono::system_clock::now().time_since_epoch())
328  .count()));
329  xmlOut.addTextElementToData(
330  "ready",
331  theDataManager_ != nullptr && theDataManager_->isReady() ? "1" : "0");
332 
333  if(theDataManager_ != nullptr)
334  {
335  auto addProcessor = [&xmlOut](const std::string& role,
336  const std::string& bufferName,
337  const DataProcessor* processor,
338  unsigned int queued,
339  unsigned int capacity) {
340  xercesc::DOMElement* el = xmlOut.addTextElementToData("processor", "");
341  xmlOut.addTextElementToParent("name", processor->getProcessorID(), el);
342  xmlOut.addTextElementToParent("role", role, el);
343  xmlOut.addTextElementToParent("buffer", bufferName, el);
344  xmlOut.addTextElementToParent(
345  "packets", std::to_string(processor->getStatPackets()), el);
346  xmlOut.addTextElementToParent(
347  "bytes", std::to_string(processor->getStatBytes()), el);
348  xmlOut.addTextElementToParent(
349  "errors", std::to_string(processor->getStatErrors()), el);
350  xmlOut.addTextElementToParent(
351  "busyNanos", std::to_string(processor->getStatBusyNanos()), el);
352  xmlOut.addTextElementToParent("queued", std::to_string(queued), el);
353  xmlOut.addTextElementToParent("capacity", std::to_string(capacity), el);
354  for(auto const& extra : processor->getExtraStatus())
355  xmlOut.addTextElementToParent(extra.first, extra.second, el);
356  };
357 
358  for(auto const& bufferPair : theDataManager_->getBuffers())
359  {
360  const auto& buffer = bufferPair.second;
361  for(auto const* producer : buffer.producers_)
362  {
363  unsigned int queued = 0, capacity = 0;
364  if(buffer.buffer_ != nullptr)
365  {
366  try
367  {
368  capacity = buffer.buffer_->getProducerBufferSize(
369  producer->getProcessorID());
370  queued = buffer.buffer_->getProducerWrittenBuffers(
371  producer->getProcessorID());
372  }
373  catch(...)
374  {
375  } // producer not registered yet (before Configure)
376  }
377  addProcessor(
378  "producer", bufferPair.first, producer, queued, capacity);
379  }
380  for(auto const* consumer : buffer.consumers_)
381  addProcessor("consumer", bufferPair.first, consumer, 0, 0);
382  }
383  }
384  }
385  else if(
386  requestType == "setUserPreferences" &&
387  userInfo.username_ !=
388  "" /*from allow no user*/) // ################################################################################################################
389  {
390  __SUP_COUT__ << "userInfo.username_: " << userInfo.username_ << __E__;
391  std::string fullPath =
392  (std::string)PREFERENCES_PATH + userInfo.username_ + PREFERENCES_FILE_EXT;
393  __SUP_COUT__ << "fullPath: " << fullPath << __E__;
394 
395  std::string radioSelect = CgiDataUtilities::getData(cgiIn, "radioSelect");
396  std::string autoRefresh = CgiDataUtilities::getData(cgiIn, "autoRefresh");
397  std::string autoHide = CgiDataUtilities::getData(cgiIn, "autoHide");
398  std::string hardRefresh = CgiDataUtilities::getData(cgiIn, "hardRefresh");
399  std::string autoRefreshPeriod =
400  CgiDataUtilities::getData(cgiIn, "autoRefreshPeriod");
401 
402  __SUP_COUT__ << "radioSelect: " << radioSelect << __E__;
403  __SUP_COUT__ << "autoRefresh: " << autoRefresh << __E__;
404  __SUP_COUT__ << "autoHide: " << autoHide << __E__;
405  __SUP_COUT__ << "hardRefresh: " << hardRefresh << __E__;
406  __SUP_COUT__ << "autoRefreshPeriod: " << autoRefreshPeriod << __E__;
407 
408  // read existing
409  FILE* fp = fopen(fullPath.c_str(), "r");
410  if(fp)
411  {
412  char line[100];
413  char val[100];
414 
415  fgets(line, 100, fp);
416  sscanf(line, "%*s %s", val);
417  if(radioSelect == "")
418  radioSelect = val;
419 
420  fgets(line, 100, fp);
421  sscanf(line, "%*s %s", val);
422  if(autoRefresh == "")
423  autoRefresh = val;
424 
425  fgets(line, 100, fp);
426  sscanf(line, "%*s %s", val);
427  if(autoHide == "")
428  autoHide = val;
429 
430  fgets(line, 100, fp);
431  sscanf(line, "%*s %s", val);
432  if(hardRefresh == "")
433  hardRefresh = val;
434 
435  fgets(line, 100, fp);
436  sscanf(line, "%*s %s", val);
437  if(autoRefreshPeriod == "")
438  autoRefreshPeriod = val;
439 
440  fclose(fp);
441  }
442 
443  // write new
444  fp = fopen(fullPath.c_str(), "w");
445  if(fp)
446  {
447  fprintf(fp, "radioSelect %s\n", radioSelect.c_str());
448  fprintf(fp, "autoRefresh %s\n", autoRefresh.c_str());
449  fprintf(fp, "autoHide %s\n", autoHide.c_str());
450  fprintf(fp, "hardRefresh %s\n", hardRefresh.c_str());
451  fprintf(fp, "autoRefreshPeriod %s\n", autoRefreshPeriod.c_str());
452  fclose(fp);
453  }
454  else
455  __SUP_COUT_ERR__ << "Failure writing preferences to file: " << fullPath
456  << __E__;
457  }
458  else if(
459  requestType ==
460  "getUserPreferences") // ################################################################################################################
461  {
462  __SUP_COUT__ << "Next is userinfo" << __E__;
463  __SUP_COUT__ << "userInfo.username_: " << userInfo.username_ << __E__;
464  std::string fullPath =
465  (std::string)PREFERENCES_PATH + userInfo.username_ + PREFERENCES_FILE_EXT;
466  __SUP_COUT__ << "fullPath: " << fullPath << __E__;
467 
468  FILE* fp = fopen(fullPath.c_str(), "r");
469  if(fp)
470  {
471  char line[100];
472  // char val[100];
473  int val;
474 
475  fgets(line, 100, fp);
476  sscanf(line, "%*s %d", &val);
477  if(val < 0 || val > 3)
478  val = 0; // FIXME.. value can get corrupt...
479  xmlOut.addTextElementToData("radioSelect", std::to_string(val));
480  fgets(line, 100, fp);
481  sscanf(line, "%*s %d", &val);
482  xmlOut.addTextElementToData("autoRefresh", std::to_string(val));
483  fgets(line, 100, fp);
484  sscanf(line, "%*s %d", &val);
485  xmlOut.addTextElementToData("autoHide", std::to_string(val));
486  fgets(line, 100, fp);
487  sscanf(line, "%*s %d", &val);
488  xmlOut.addTextElementToData("hardRefresh", std::to_string(val));
489  fgets(line, 100, fp);
490  sscanf(line, "%*s %d", &val);
491  xmlOut.addTextElementToData("autoRefreshPeriod", std::to_string(val));
492  fclose(fp);
493  }
494  else
495  {
496  // else assume user has no preferences yet
497  xmlOut.addTextElementToData("radioSelect", "");
498  xmlOut.addTextElementToData("autoRefresh", "");
499  xmlOut.addTextElementToData("autoHide", "");
500  xmlOut.addTextElementToData("hardRefresh", "");
501  xmlOut.addTextElementToData("autoRefreshPeriod", "");
502  }
503  __SUP_COUT__ << "Done with preferences!" << __E__;
504  }
505  else if(
506  requestType ==
507  "getDirectoryContents") // ################################################################################################################
508  {
509  // return directory structure for requested path, types are "dir" and "file"
510  std::string rootpath =
511  std::string(ROOT_BROWSER_PATH) +
512  "/"; // Base directory where the Visualizer will look for files
513  std::string path = CgiDataUtilities::postData(cgiIn, "Path");
514  boost::regex re("%2F");
515  path = boost::regex_replace(path, re, "/"); // Dario: should be transparent for
516  // Ryan's purposes but required by Extjs
517 
520 
521  // return 1 if user has access to admin controls, else 0
522  char permStr[10];
523  sprintf(permStr,
524  "%d",
525  userInfo.permissionLevel_ >=
527  "rootAdminControls"));
528  xmlOut.addTextElementToData("permissions", permStr); // add permissions
531 
532  std::string dirpath = rootpath + path;
533  // If I am not looking for a file but just for the dir with the premade views
534  if(path == "/" + PRE_MADE_ROOT_CFG_DIR + "/")
535  dirpath = ROOT_DISPLAY_CONFIG_PATH;
536 
537  if(path.find("/" + PRE_MADE_ROOT_CFG_DIR + "/") ==
538  0) // ROOT config path must start the path
539  dirpath = std::string(ROOT_DISPLAY_CONFIG_PATH) + "/" +
540  path.substr(PRE_MADE_ROOT_CFG_DIR.length() + 2);
541 
542  // If looking for the History virtual dir, remap to ROOT_BROWSER_PATH
543  if(path == "/" + HISTORY_DIR + "/")
544  dirpath = std::string(ROOT_BROWSER_PATH) + "/";
545  else if(path.find("/" + HISTORY_DIR + "/") == 0)
546  dirpath = std::string(ROOT_BROWSER_PATH) + "/" +
547  path.substr(HISTORY_DIR.length() + 2);
548 
550  __SUP_COUT__ << "rootpath:-" << rootpath << "-path:-" << path << "-dirpath:-"
551  << dirpath << "-" << __E__;
552 
553  DIR* pDIR;
554  struct dirent* entry;
555  bool isNotRtCfg;
556  bool isDir;
557  if((pDIR = opendir(dirpath.c_str())))
558  {
559  xmlOut.addTextElementToData("path", path);
560  xmlOut.addTextElementToData("headOfSearch", "located");
561 
562  // add LIVE if path is / and DQM is active
563  // add Pre-made Views if path is / and ROOT_DISPLAY_CONFIG_PATH isnt already
564  // there
565  if(theDataManager_ != nullptr)
566  __COUT__ << "path-" << path << "-DM: " << theDataManager_
567  << " Live: " << theDataManager_->getLiveDQMHistos() << std::endl;
568  if(path == "/")
569  {
570  // Add live histos, but only while the data manager is taking data.
571  // The browser polls getDataStatus and refreshes this listing when the
572  // running state changes.
573  if(theDataManager_ != nullptr && theDataManager_->isReady())
574  xmlOut.addTextElementToData("dir",
575  LIVEDQM_DIR + ".root"); // add to xml
576 
577  // check for ROOT_DISPLAY_CONFIG_PATH
578  DIR* pRtDIR = opendir(ROOT_DISPLAY_CONFIG_PATH);
579  bool recheck = false;
580  if(!pRtDIR) // if doesn't exist, make it
581  {
582  recheck = true;
583  if(mkdir(ROOT_DISPLAY_CONFIG_PATH,
584  S_IRWXU | (S_IRGRP | S_IXGRP) |
585  (S_IROTH | S_IXOTH))) // mode = drwx r-x r-x
586  __SUP_COUT__ << "Failed to make directory for pre made views: "
587  << ROOT_DISPLAY_CONFIG_PATH << __E__;
588  }
589  else
590  closedir(pRtDIR); // else close and display
591 
592  if(!recheck || (pRtDIR = opendir(ROOT_DISPLAY_CONFIG_PATH)))
593  {
596  xmlOut.addTextElementToData("dir",
597  PRE_MADE_ROOT_CFG_DIR); // add to xml
598  if(recheck)
599  closedir(pRtDIR);
600  }
601 
602  xmlOut.addTextElementToData("dir", HISTORY_DIR); // add to xml
603  }
605  if(path != "/")
606  while((entry = readdir(pDIR)))
607  {
608  //__SUP_COUT__ << int(entry->d_type) << " " << entry->d_name << "\n" <<
609  // __E__;
610  if(entry->d_name[0] != '.' &&
611  (entry->d_type ==
612  0 || // 0 == UNKNOWN (which can happen - seen in SL7 VM)
613  entry->d_type == 4 ||
614  entry->d_type == 8))
615  {
616  //__SUP_COUT__ << int(entry->d_type) << " " << entry->d_name << "\n"
617  //<< __E__;
618  isNotRtCfg =
619  std::string(entry->d_name).find(".rcfg") == std::string::npos;
620  isDir = false;
621 
622  if(entry->d_type == 0)
623  {
624  // unknown type .. determine if directory
626  DIR* pTmpDIR = opendir((dirpath + entry->d_name).c_str());
627  if(pTmpDIR)
628  {
630  isDir = true;
631  closedir(pTmpDIR);
632  }
633  // else //assume file
634  }
635 
636  if((entry->d_type == 8 ||
637  (!isDir && entry->d_type == 0)) // file type
638  && std::string(entry->d_name).find(".root") ==
639  std::string::npos &&
640  isNotRtCfg)
641  continue; // skip if not a root file or a config file
642  else if(entry->d_type == 4)
643  isDir = true; // flag directory types
644 
645  xmlOut.addTextElementToData(
646  isDir ? "dir" : (isNotRtCfg ? "dir" : "file"), entry->d_name);
647  }
648  }
649  closedir(pDIR);
650  }
651  else
652  __SUP_COUT__ << "Failed to access directory contents!" << __E__;
653  // std::ostringstream* out ;
654  // xmlOut.outputXmlDocument((std::ostringstream*) out, true);
655  }
656  else if(
657  requestType ==
658  "getRoot") // ################################################################################################################
659  {
660  // return directory structure for requested ROOT path, types are "dir" and "file"
661  std::string path = CgiDataUtilities::postData(cgiIn, "RootPath");
662  __SUP_COUTV__(path);
663 
664  // Strip History virtual directory prefix for file resolution, keep original path for response
665  std::string filePath = path;
666  if(filePath.find("/" + HISTORY_DIR + "/") == 0)
667  filePath = filePath.substr(HISTORY_DIR.length() + 1);
668 
669  unsigned splitter =
670  filePath.find(".root") + 5; // 5 = std::string(".root").size();
671  std::string rootFileName =
672  std::string(__ENV__("ROOT_BROWSER_PATH")) + filePath.substr(0, splitter);
673  __SUP_COUTV__(rootFileName);
674 
675  std::string rootDirectoryName =
676  filePath.substr(splitter, filePath.length() - splitter);
677  __SUP_COUTV__(rootDirectoryName);
678 
679  // std::string fullPathToObject = rootFileName + ":" + rootDirectoryName;
680  // __SUP_COUTV__(fullPathToObject);
681 
682  bool isLiveDQM = (path.find("/" + LIVEDQM_DIR + ".root/") == 0) ? true : false;
683  __SUP_COUTV__(isLiveDQM);
684 
685  if(isLiveDQM)
686  {
687  // Skip the LIVE_TOP_DIR level: "/" lists the streams directly. Older saved
688  // views that spell out the level keep working.
689  const std::string top = "/" + LIVE_TOP_DIR;
690  if(rootDirectoryName.empty() || rootDirectoryName == "/")
691  rootDirectoryName = top;
692  else if(rootDirectoryName != top &&
693  rootDirectoryName.rfind(top + "/", 0) != 0)
694  rootDirectoryName = top + rootDirectoryName;
695  __SUP_COUTV__(rootDirectoryName);
696  }
697 
698  TFile* rootFile = nullptr;
699  TObject* tObject = nullptr;
700  TDirectory* tDirectory = nullptr;
701 
702  if(!isLiveDQM) // If it is not from LIVE_DQM
703  {
704  rootFile = TFile::Open(rootFileName.c_str());
705 
706  if(rootFile == nullptr || !rootFile->IsOpen())
707  {
708  __SUP_SS__ << "Failed to access ROOT file: " << rootFileName << __E__;
709  __SUP_SS_THROW__;
710  }
711  // Own the file for the rest of this block so every exit path closes it.
712  // Before this guard the single-object branch returned without closing,
713  // leaking one descriptor per History plot request.
714  std::unique_ptr<TFile> rootFileGuard(rootFile);
715  // First I check if I can find the object to return directly. If not an object
716  // it is a directory
717  if((tObject = rootFile->Get(rootDirectoryName.c_str())) !=
718  nullptr || //for backwards compatibility
719  (rootDirectoryName.size() &&
720  rootDirectoryName[0] == '/' && //for newer root, remove leading '/'
721  (tObject = rootFile->Get(rootDirectoryName.substr(1).c_str())) !=
722  nullptr))
723  {
724  if(tObject->IsA() == TCanvas::Class())
725  {
726  static_cast<TCanvas*>(tObject)->Modified();
727  static_cast<TCanvas*>(tObject)->Update();
728  }
729  TString json = TBufferJSON::ConvertToJSON(tObject);
730  TBufferFile tBuffer(TBuffer::kWrite);
731  tObject->Streamer(tBuffer);
732  std::string hexString = BinaryStringMacros::binaryStringToHexString(
733  tBuffer.Buffer(), tBuffer.Length());
734 
735  __SUP_COUT__ << "Returning object from file '" << tObject->GetName()
736  << "' of class '" << tObject->ClassName() << __E__;
737 
738  xmlOut.addTextElementToData("path", path);
739  xmlOut.addTextElementToData("rootType", tObject->ClassName());
740  xmlOut.addTextElementToData("rootData", hexString);
741  xmlOut.addTextElementToData("rootJSON", json.Data());
742  }
743  else if((tDirectory = rootFile->GetDirectory(rootDirectoryName.c_str())) !=
744  nullptr)
745  {
746  TKey* key;
747  TIter next(tDirectory->GetListOfKeys());
748  xmlOut.addTextElementToData("path", path);
749  while((key = (TKey*)next()))
750  {
751  TString s = key->GetName();
752  TRegexp re("*", kTRUE);
753  if(s.Index(re) == kNPOS)
754  continue;
755  __SUP_COUT__ << "Class Name: " << key->GetClassName() << __E__;
756  xmlOut.addTextElementToData(
757  (std::string(key->GetClassName()).find("Directory") !=
758  std::string::npos ||
759  std::string(key->GetClassName()) == "TTree" ||
760  std::string(key->GetClassName()).find("TBranch") !=
761  std::string::npos) // == "TBranchElement")
762  ? "dir"
763  : "file",
764  key->GetName());
765 
766  if(TTEST(
767  50)) //enable to view json content of each object in directory
768  {
769  tObject = key->ReadObj();
770  __SUP_COUT__ << "JSON : " << key->GetClassName() << __E__;
771 
772  TString json = TBufferJSON::ConvertToJSON(tObject);
773  TBufferFile tBuffer(TBuffer::kWrite);
774  tObject->Streamer(tBuffer);
775  std::string hexString =
777  tBuffer.Length());
778 
779  __SUP_COUT__ << "Returning directory object from file '"
780  << tObject->GetName() << "' of class '"
781  << tObject->ClassName() << __E__;
782 
783  __SUP_COUTV__(json.Data());
784  }
785  }
786  }
787  else
788  __SUP_COUT_ERR__ << "Failed to find object " << rootDirectoryName
789  << " in " << rootFileName << __E__;
790  return; // rootFileGuard closes the file
791  }
792  // LIVE DQM PLOTS
793  else if(theDataManager_ != nullptr && theDataManager_->isReady())
794  {
795  if(theDataManager_ != nullptr)
796  theDataManager_->setDoNotStop(true);
797  else
798  return;
799  __SUP_COUT__ << "Attempting to get LIVE ROOT object." << __E__;
800 
801  std::vector<DQMHistosBase*> dqmConsumers = theDataManager_->getLiveDQMs();
802  tObject = nullptr;
803  for(auto const& consumer : dqmConsumers)
804  {
805  rootFile = consumer->getFile();
806  __SUP_COUT__ << "LIVE file name: " << rootFile->GetName() << __E__;
807  if(rootFile == nullptr || !rootFile->IsOpen())
808  {
809  __SUP_SS__ << "Failed to access LIVE ROOT file: " << rootFileName
810  << __E__;
811  theDataManager_->setDoNotStop(false);
812  return;
813  }
814  // If I find an object then I stream it and return
815  if((tObject = rootFile->Get(rootDirectoryName.c_str())) != nullptr)
816  {
817  __SUP_COUT__ << "Object class name: " << tObject->ClassName()
818  << __E__;
819  std::string tmpClassName = tObject->ClassName();
820  TString json;
821  TBufferFile tBuffer(TBuffer::kWrite);
822  if(tObject->IsA() == TCanvas::Class())
823  {
824  static_cast<TCanvas*>(tObject)->Modified();
825  static_cast<TCanvas*>(tObject)->Update();
826  }
827  { // Only locking when converting the object
828  std::unique_lock<std::mutex> lock(
829  static_cast<DQMHistosConsumerBase*>(consumer)
830  ->getFillHistoMutex());
831  json = TBufferJSON::ConvertToJSON(tObject);
832  tObject->Streamer(tBuffer);
833  }
834  std::string hexString = BinaryStringMacros::binaryStringToHexString(
835  tBuffer.Buffer(), tBuffer.Length());
836 
837  __SUP_COUT__ << "Returning object '" << tObject->GetName()
838  << "' of class '" << tObject->ClassName() << __E__;
839 
840  //__SUP_COUT__ << "Data: " << json.Data() << std::endl;
841  xmlOut.addTextElementToData("path", path);
842  xmlOut.addTextElementToData("rootType", tObject->ClassName());
843  xmlOut.addTextElementToData("rootData", hexString);
844  xmlOut.addTextElementToData("rootJSON", json.Data());
845 
846  theDataManager_->setDoNotStop(false);
847  return;
848  }
849  }
850  // If I didn't find any object in the file, then it must be a directory!
851  std::map<std::string, std::string> dirList;
852 
853  for(auto const& consumer : dqmConsumers)
854  {
855  __SUP_COUT__ << "Attempting to get LIVE ROOT directory." << __E__;
856  rootFile = consumer->getFile();
857  __SUP_COUT__ << "LIVE file name: " << rootFile->GetName() << __E__;
858  if(rootFile == nullptr || !rootFile->IsOpen())
859  {
860  __SUP_SS__ << "Failed to access LIVE ROOT file: " << rootFileName
861  << __E__;
862  xmlOut.addTextElementToData("Warning", ss.str());
863  theDataManager_->setDoNotStop(false);
864  return;
865  }
866  if((tDirectory = rootFile->GetDirectory(rootDirectoryName.c_str())) !=
867  nullptr)
868  {
869  xmlOut.addTextElementToData("path", path);
870  __SUP_COUT__ << "Directory found getting the content!" << __E__;
871  TRegexp re("*", kTRUE);
872  TObject* obj;
873  TIter nextobj(tDirectory->GetList());
874  while((obj = (TObject*)nextobj()))
875  {
876  TString s = obj->GetName();
877  if(s.Index(re) == kNPOS)
878  continue;
879  __SUP_COUT__ << "Class Name: " << obj->IsA()->GetName() << __E__;
880  dirList[obj->GetName()] =
881  (std::string(obj->IsA()->GetName()).find("Directory") !=
882  std::string::npos ||
883  std::string(obj->IsA()->GetName()) == "TTree" ||
884  std::string(obj->IsA()->GetName()).find("TBranch") !=
885  std::string::npos) // == "TBranchElement")
886  ? "dir"
887  : "file";
888  }
889  }
890  }
891  for(auto const& dir : dirList)
892  {
893  xmlOut.addTextElementToData(dir.second, dir.first);
894  __SUP_COUT__ << "Class Name: " << dir.second << " Object: " << dir.first
895  << __E__;
896  }
897  }
898 
899  } // END LORENZO GET ROOT
900  // else if(
901  // requestType ==
902  // "RyangetRoot")
903  // //################################################################################################################
904  // {
905  // // return directory structure for requested ROOT path, types are "dir" and "file"
906  // std::string path = CgiDataUtilities::postData(cgiIn, "RootPath");
907 
908  // //////////////////////////////////////////////////////////////////
909  // // DARIO
910  // //////////////////////////////////////////////////////////////////
911  // ss.str("");
912  // ss << "PID: " << ::getpid();
913  // // STDLINE(ss.str(),ACCyan) ;
914  // boost::regex re1("%2F");
915  // path = boost::regex_replace(
916  // path, re1, "/"); // Dario: should be transparent for Ryan's purposes but
917  // // required by Extjs
918  // boost::regex re2("%20");
919  // path = boost::regex_replace(
920  // path, re2, " "); // Dario: should be transparent for Ryan's purposes but
921  // // required by Extjs
922  // boost::regex re3("%3A");
923  // path =
924  // boost::regex_replace(path, re3, ""); // Dario: should be transparent for
925  // // Ryan's purposes but required by Extjs
926  // ss.str("");
927  // ss << "path : " << path;
928  // // STDLINE(ss.str(),ACCyan) ;
929  // //////////////////////////////////////////////////////////////////
930  // // END DARIO
931  // //////////////////////////////////////////////////////////////////
932 
933  // std::string fullPath = std::string(__ENV__("ROOT_BROWSER_PATH")) + path;
934  // __SUP_COUTV__(fullPath);
935 
936  // const size_t rootExtensionStart = fullPath.find(".root");
937  // const size_t rootExtensionEnd = rootExtensionStart + std::string(".root").size();
938 
939  // std::string rootFileName = fullPath.substr(0, rootExtensionEnd);
940 
941  // __SUP_COUTV__(rootFileName);
942  // std::string fullPathToObject =
943  // rootFileName + ":" +
944  // fullPath.substr(rootExtensionEnd, fullPath.size() - rootExtensionEnd + 1);
945 
946  // __SUP_COUTV__(fullPathToObject);
947  // std::string::size_type LDQM_pos = path.find("/" + LIVEDQM_DIR + ".root/");
948  // __SUP_COUTV__(LDQM_pos);
949 
950  // TFile* rootFile = nullptr;
951  // if(LDQM_pos == std::string::npos) // If it is not from LIVE_DQM
952  // {
953  // __SUP_COUTV__(rootFileName);
954  // rootFile = TFile::Open(rootFileName.c_str());
955 
956  // if(rootFile == nullptr || !rootFile->IsOpen())
957  // {
958  // __SUP_SS__ << "Failed to access ROOT file: " << rootFileName << __E__;
959  // __SUP_SS_THROW__;
960  // }
961  // }
962  // else
963  // {
964  // if(theDataManager_ == nullptr || !theDataManager_->isReady())
965  // return;
966  // theDataManager_->setDoNotStop(true);
967  // if(theDataManager_ != nullptr &&
968  // theDataManager_->getLiveDQMHistos() != nullptr)
969  // {
970  // __SUP_COUT__ << "Attempting to get LIVE ROOT object." << __E__;
971  // __SUP_COUTV__(fullPathToObject);
972  // fullPathToObject = path.substr(("/" + LIVEDQM_DIR + ".root").length());
973  // __SUP_COUTV__(fullPathToObject);
974  // rootFile = theDataManager_->getLiveDQMHistos()->getFile();
975 
976  // __SUP_COUT__ << "LIVE file name: " << rootFile->GetName() << __E__;
977 
978  // if(rootFile == nullptr || !rootFile->IsOpen())
979  // {
980  // __SUP_SS__ << "Failed to access LIVE ROOT file: " << rootFileName
981  // << __E__;
982  // __SUP_COUT__ << ss.str();
983  // xmlOut.addTextElementToData("Warning", ss.str());
984  // theDataManager_->setDoNotStop(false);
985  // return; // do not treat LIVE root file missing as error, .. assume
986  // // just not Running
987  // }
988  // }
989  // else
990  // {
991  // __SUP_SS__ << "Failed to access LIVE ROOT file: " << rootFileName
992  // << __E__;
993  // __SUP_COUT__ << ss.str();
994  // xmlOut.addTextElementToData("Warning", ss.str());
995  // theDataManager_->setDoNotStop(false);
996  // return; // do not treat LIVE root file missing as error, .. assume just
997  // // not Running
998  // }
999  // }
1000 
1001  // // at this point initial ROOT object has been successfully opened
1002 
1003  // xmlOut.addTextElementToData("path", path);
1004 
1005  // TDirectory* directory = rootFile->GetDirectory(fullPathToObject.c_str());
1006  // __SUP_COUT__ << "Getting dir pointer: " << directory
1007  // << " dir name: " << fullPathToObject << __E__;
1008  // TObject* tobject = nullptr;
1009 
1010  // if(!directory) // if not directory yet, peak at object for TTree or
1011  // // TBranchElement with children
1012  // {
1013  // ///////////////////////////////////////////////////////////////////////////
1014  // // TREE HANDLING
1015  // // if TTree or TBranchElement with children, then treat as a directory
1016  // // else if TBranchElement without children, then treat as leaf ROOT object
1017 
1018  // fullPathToObject = fullPath.substr(
1019  // rootExtensionEnd); // re-purpose fullPathToObject as path within TTree
1020 
1021  // std::vector<std::string> splitTTreePath =
1022  // StringMacros::getVectorFromString(fullPathToObject, {'/'});
1023  // __SUP_COUTV__(StringMacros::vectorToString(splitTTreePath));
1024 
1025  // unsigned int spliti = 0;
1026  // while(spliti < splitTTreePath.size() && splitTTreePath[spliti].size() == 0)
1027  // ++spliti; // search for first non-empty
1028 
1029  // if(spliti < splitTTreePath.size())
1030  // {
1031  // __SUP_COUTV__(splitTTreePath[spliti]);
1032  // tobject = (TObject*)rootFile->Get(splitTTreePath[spliti].c_str());
1033  // ++spliti; // search for next non-empty
1034  // }
1035 
1036  // if(tobject == nullptr)
1037  // {
1038  // __SUP_SS__ << "Failed to access ROOT sub path: " << fullPathToObject
1039  // << __E__;
1040  // __SUP_SS_THROW__;
1041  // }
1042  // __SUP_COUTV__(tobject->ClassName());
1043 
1044  // if(std::string(tobject->ClassName()) == "TTree" ||
1045  // std::string(tobject->ClassName()).find("TBranch") !=
1046  // std::string::npos || // == "TBranchElement" ||
1047  // std::string(tobject->ClassName()).find("TDirectory") != std::string::npos)
1048  // {
1049  // // continue traversing name split
1050  // do
1051  // {
1052  // while(spliti < splitTTreePath.size() &&
1053  // splitTTreePath[spliti].size() == 0)
1054  // ++spliti; // search for next non-empty
1055  // if(spliti >= splitTTreePath.size())
1056  // break; // reached end of traversal!
1057 
1058  // __SUP_COUTV__(splitTTreePath[spliti]);
1059  // __SUP_COUT__ << "Parent class = " << (tobject->ClassName()) << __E__;
1060  // if(std::string(tobject->ClassName()) == "TTree")
1061  // tobject = (TObject*)((TTree*)tobject)
1062  // ->GetBranch(splitTTreePath[spliti].c_str());
1063  // else if(std::string(tobject->ClassName()).find("TBranch") !=
1064  // std::string::npos)
1065  // tobject = (TObject*)((TBranchElement*)tobject)
1066  // ->FindBranch(splitTTreePath[spliti].c_str());
1067  // else if(std::string(tobject->ClassName()).find("TDirectory") !=
1068  // std::string::npos)
1069  // tobject = (TObject*)((TDirectoryFile*)tobject)
1070  // ->Get(splitTTreePath[spliti].c_str());
1071 
1072  // ++spliti; // search for next non-empty
1073  // } while(tobject);
1074 
1075  // if(tobject == nullptr)
1076  // {
1077  // __SUP_SS__ << "Failed to access root sub path: " << fullPathToObject
1078  // << __E__;
1079  // __SUP_SS_THROW__;
1080  // }
1081 
1082  // __SUP_COUTV__(tobject->ClassName());
1083 
1084  // // now at path's target element with tobject
1085  // // if no branches, then "file" and tobject stringified
1086  // // else "dir"
1087 
1088  // TObjArray* objects = nullptr;
1089 
1090  // if(std::string(tobject->ClassName()) == "TTree")
1091  // objects = ((TTree*)tobject)->GetListOfBranches();
1092  // else if(std::string(tobject->ClassName()).find("TBranch") !=
1093  // std::string::npos) //== "TBranchElement")
1094  // objects = ((TBranchElement*)tobject)->GetListOfBranches();
1095 
1096  // if(objects != nullptr && !objects->IsEmpty())
1097  // {
1098  // __SUP_COUT__ << "Handling as TTree/TBranchElement directory" << __E__;
1099 
1100  // // treat like a directory, and return branches
1101  // TObject* obj;
1102  // TIter nextobj(objects->MakeIterator());
1103  // TRegexp re("*", kTRUE);
1104  // while((obj = (TObject*)nextobj()))
1105  // {
1106  // std::string name = obj->GetName();
1107  // TString s = name;
1108  // if(s.Index(re) == kNPOS)
1109  // continue;
1110 
1111  // __SUP_COUT__ << "Child class Name: " << obj->IsA()->GetName()
1112  // << " " << name << __E__;
1113 
1114  // if(std::string(obj->IsA()->GetName()).find("TBranch") !=
1115  // std::string::npos) // == "TBranchElement")
1116  // {
1117  // // decide if leave based on children branches
1118  // __SUP_COUT__
1119  // << "Child '" << name << "' of type '"
1120  // << ((TBranchElement*)obj)->GetTypeName() << "' isLeaf="
1121  // << ((TBranchElement*)obj)->GetListOfBranches()->IsEmpty()
1122  // << __E__;
1123 
1124  // xmlOut.addTextElementToData(
1125  // (((TBranchElement*)obj)->GetListOfBranches()->IsEmpty())
1126  // ? "file"
1127  // : "dir",
1128  // name);
1129  // }
1130  // else // handle normal way
1131  // {
1132  // xmlOut.addTextElementToData(
1133  // (std::string(obj->IsA()->GetName()).find("Directory") !=
1134  // std::string::npos ||
1135  // std::string(obj->IsA()->GetName()) == "TTree")
1136  // ? "dir"
1137  // : "file",
1138  // name);
1139  // }
1140  // }
1141  // theDataManager_->setDoNotStop(false);
1142  // return;
1143  // } // done handling TTree branches
1144  // } // end TTree and branch handling
1145  // else if(spliti < splitTTreePath.size())
1146  // {
1147  // __COUTV__(fullPathToObject);
1148  // // if more name to mystery object (likely TDirectoryFile), then attempt to
1149  // // get full subpath
1150  // tobject = (TObject*)rootFile->Get(fullPathToObject.c_str());
1151  // }
1152 
1153  // // at this point have tobject to stringify
1154  // } // peaking for TTree
1155 
1156  // if(directory == nullptr) // It MUST be an object to be serialized! tobject !=
1157  // // nullptr at this point.
1158  // {
1159  // __SUP_COUT__ << "This is not a directory!" << __E__;
1160 
1161  // if(tobject == nullptr)
1162  // {
1163  // __SUP_SS__
1164  // << "Something is wrong. Failed to access ROOT TObject at path: "
1165  // << fullPath << __E__;
1166  // __SUP_SS_THROW__;
1167  // }
1168 
1169  // // TObject* tobjectClone = nullptr;
1170 
1171  // if(tobject != nullptr) // turns out was a root object path
1172  // {
1173  // // ignore lock, because Lore says only crashed with Canvas
1174 
1175  // // FIXME -- check this new histo and gDirectory->Get for memory leak!
1176  // bool doJSONobject = false;
1177  // TH1F* h8 = nullptr;
1178  // std::string tmpClassName = tobject->ClassName();
1179  // if(tmpClassName.find("TBranch") != std::string::npos)
1180  // {
1181  // __COUT__ << "Attempting to plot '" << tobject->ClassName()
1182  // << "' type." << __E__;
1183 
1184  // h8 = new TH1F();
1185  // TTree* t3 = ((TBranch*)tobject)->GetTree();
1186  // //__COUT__ << "Attempting to plot '" << t3 << "' type." << __E__;
1187  // //__COUT__ << "JSON=" << TBufferJSON::ConvertToJSON(h8).Data() <<
1188  // //__E__;
1189  // t3->Draw("Value>>h8", "", "goff");
1190  // tobject = gDirectory->Get("h8");
1191 
1192  // __COUT__ << "Attempting to plot '" << tobject->ClassName()
1193  // << "' type." << __E__;
1194  // doJSONobject = true;
1195  // }
1196 
1197  // TString json;
1198  // TBufferFile tBuffer(TBuffer::kWrite);
1199  // if(theDataManager_ != nullptr &&
1200  // theDataManager_->getLiveDQMHistos() != nullptr && LDQM_pos == 0)
1201  // {
1202  // if(tobject->IsA() == TCanvas::Class())
1203  // {
1204  // static_cast<TCanvas*>(tobject)->Modified();
1205  // static_cast<TCanvas*>(tobject)->Update();
1206  // }
1207  // std::unique_lock<std::mutex> lock(
1208  // static_cast<DQMHistosConsumerBase*>(
1209  // theDataManager_->getLiveDQMHistos())
1210  // ->getFillHistoMutex());
1211  // json = TBufferJSON::ConvertToJSON(tobject);
1212  // tobject->Streamer(tBuffer);
1213  // }
1214  // else
1215  // {
1216  // // No need to lock from file!
1217  // json = TBufferJSON::ConvertToJSON(tobject);
1218  // tobject->Streamer(tBuffer);
1219  // }
1220 
1221  // std::string hexString = BinaryStringMacros::binaryStringToHexString(
1222  // tBuffer.Buffer(), tBuffer.Length());
1223 
1224  // __SUP_COUT__ << "Returning object '" << tobject->GetName()
1225  // << "' of class '" << tobject->ClassName() << __E__;
1226 
1227  // //__SUP_COUT__ << "Data: " << json.Data() << std::endl;
1228  // xmlOut.addTextElementToData("rootType",
1229  // doJSONobject ? "JSON" : tobject->ClassName());
1230  // xmlOut.addTextElementToData("rootData", hexString);
1231  // xmlOut.addTextElementToData("rootJSON", json.Data());
1232 
1233  // if(h8 != nullptr)
1234  // delete h8;
1235  // }
1236  // else
1237  // __SUP_COUT_ERR__ << "Failed to access:-" << fullPathToObject << "-"
1238  // << __E__;
1239  // STDLINE("Done with it!", ACBlue);
1240  // }
1241  // else // handle as directory
1242  // {
1243  // __SUP_COUT__ << "directory found getting the content!" << __E__;
1244  // STDLINE("Directory found getting the content!", ACGreen);
1245  // TRegexp re("*", kTRUE);
1246  // if(LDQM_pos == 0)
1247  // {
1248  // TObject* obj;
1249  // TIter nextobj(directory->GetList());
1250  // while((obj = (TObject*)nextobj()))
1251  // {
1252  // TString s = obj->GetName();
1253  // if(s.Index(re) == kNPOS)
1254  // continue;
1255  // __SUP_COUT__ << "Class Name: " << obj->IsA()->GetName() << __E__;
1256 
1257  // xmlOut.addTextElementToData(
1258  // (std::string(obj->IsA()->GetName()).find("Directory") !=
1259  // std::string::npos ||
1260  // std::string(obj->IsA()->GetName()) == "TTree" ||
1261  // std::string(obj->IsA()->GetName()).find("TBranch") !=
1262  // std::string::npos) // == "TBranchElement")
1263  // ? "dir"
1264  // : "file",
1265  // obj->GetName());
1266  // // ss.str("") ; ss << "obj->GetName(): " << obj->GetName() ;
1267  // // //STDLINE(ss.str(),"") ;
1268  // }
1269  // }
1270  // else
1271  // {
1272  // TKey* key;
1273  // TIter next(directory->GetListOfKeys());
1274  // while((key = (TKey*)next()))
1275  // {
1276  // TString s = key->GetName();
1277  // if(s.Index(re) == kNPOS)
1278  // continue;
1279  // __SUP_COUT__ << "Class Name: " << key->GetClassName() << __E__;
1280  // xmlOut.addTextElementToData(
1281  // (std::string(key->GetClassName()).find("Directory") !=
1282  // std::string::npos ||
1283  // std::string(key->GetClassName()) == "TTree" ||
1284  // std::string(key->GetClassName()).find("TBranch") !=
1285  // std::string::npos) // == "TBranchElement")
1286  // ? "dir"
1287  // : "file",
1288  // key->GetName());
1289  // // ss.str("") ; ss << "key->GetName(): " << key->GetName() ;
1290  // ////STDLINE(ss.str(),"") ;
1291  // }
1292  // }
1293  // }
1294  // if(LDQM_pos == std::string::npos)
1295  // rootFile->Close();
1296 
1297  // } // end getRoot handling
1298  else if(
1299  requestType ==
1300  "getEvents") // ################################################################################################################
1301  {
1302  if(theDataManager_ == nullptr)
1303  {
1304  __SS__ << "No Data Manager instantiated." << __E__;
1305  __SS_THROW__;
1306  }
1307 
1308  int Run = atoi(cgiIn("run").c_str());
1309 
1310  __SUP_COUT__ << "getEvents for run " << Run << __E__;
1311 
1312  if(Run != (int)loadedRunNumber_ || loadedRunNumber_ == (unsigned int)-1)
1313  {
1314  theDataManager_->load("Run1684.root", "Monicelli");
1315  loadedRunNumber_ = Run;
1316  }
1317 
1318  /*DOMElement* eventsParent =*/xmlOut.addTextElementToData("events", "");
1319  // DOMElement* eventParent;
1320  // char str[40];
1321 
1322  // const Visual3DEvents& events = theDataManager_->getVisual3DEvents();
1323  // __SUP_COUT__ << "Preparing hits xml" << __E__;
1324  // int numberOfEvents = 0;
1325  // for(Visual3DEvents::const_iterator it=events.begin(); it!=events.end() &&
1326  // numberOfEvents < 10000; it++, numberOfEvents++)
1327  // {
1328  // //__SUP_COUT__ << "Event: " << numberOfEvents << __E__;
1329  // eventParent = xmlOut.addTextElementToParent("event", str,
1330  // eventsParent); const VisualHits& hits = it->getHits();
1331  // for(VisualHits::const_iterator itHits=hits.begin();
1332  // itHits!=hits.end(); itHits++)
1333  // {
1334  // sprintf(str,"%f",itHits->x);
1335  // xmlOut.addTextElementToParent("xyz_point", str, eventParent);
1336  // sprintf(str,"%f",itHits->y);
1337  // xmlOut.addTextElementToParent("xyz_point", str, eventParent);
1338  // sprintf(str,"%f",itHits->z);
1339  // xmlOut.addTextElementToParent("xyz_point", str, eventParent);
1340  // //__SUP_COUT__ << "X: " << itHits->x << " Y: " << itHits->y << "
1341  // Z:
1342  //"
1343  //<< itHits->z << __E__;
1344  // }
1345  // const VisualTracks& tracks = it->getTracks();
1346  // for(VisualTracks::const_iterator itTrks=tracks.begin();
1347  // itTrks!=tracks.end(); itTrks++)
1348  // {
1349  // sprintf(str,"%f",itTrks->slopeX);
1350  // xmlOut.addTextElementToParent("slope", str, eventParent);
1351  // sprintf(str,"%f",itTrks->slopeY);
1352  // xmlOut.addTextElementToParent("slope", str, eventParent);
1353  // sprintf(str,"%f",itTrks->interceptX);
1354  // xmlOut.addTextElementToParent("intcpt", str, eventParent);
1355  // sprintf(str,"%f",itTrks->interceptY);
1356  // xmlOut.addTextElementToParent("intcpt", str, eventParent);
1357  //
1358  // }
1359  //
1360  // }
1361  __SUP_COUT__ << "Done hits xml" << __E__;
1362  }
1363  else if(
1364  requestType ==
1365  "getGeometry") // ################################################################################################################
1366  {
1367  __SUP_COUT__ << "getGeometry" << __E__;
1368 
1369  if(theDataManager_ == nullptr)
1370  {
1371  __SS__ << "No Data Manager instantiated." << __E__;
1372  __SS_THROW__;
1373  }
1374 
1375  // FIXME -- this crashes when the file doesn't exist!
1376  theDataManager_->load("Run1684.geo", "Geometry");
1377 
1378  __SUP_COUT__ << "getGeometry" << __E__;
1379 
1380  /*DOMElement* geometryParent =*/xmlOut.addTextElementToData("geometry", "");
1381  // const Visual3DShapes& shapes =
1382  // theDataManager_->getVisual3DGeometry().getShapes();
1383  //
1384  // __SUP_COUT__ << "getGeometry" << __E__;
1385  //
1386  //
1387  // DOMElement* objectParent;
1388  // char str[40];
1389  // for(Visual3DShapes::const_iterator itShapes=shapes.begin();
1390  // itShapes!=shapes.end(); itShapes++)
1391  // {
1392  // objectParent = xmlOut.addTextElementToParent("object", str,
1393  // geometryParent);
1394  // xmlOut.addTextElementToParent("object_type", "LINE_LOOP",
1395  // objectParent); sprintf(str,"%d",itShapes->numberOfRows);
1396  // xmlOut.addTextElementToParent("object_rows", str, objectParent);
1397  // sprintf(str,"%d",itShapes->numberOfColumns);
1398  // xmlOut.addTextElementToParent("object_columns", str, objectParent);
1399  // for(Points::const_iterator itCorners=itShapes->corners.begin();
1400  // itCorners!=itShapes->corners.end(); itCorners++)
1401  // {
1402  // sprintf(str,"%f",itCorners->x);
1403  // xmlOut.addTextElementToParent("xyz_point", str, objectParent);
1404  // sprintf(str,"%f",itCorners->y);
1405  // xmlOut.addTextElementToParent("xyz_point", str, objectParent);
1406  // sprintf(str,"%f",itCorners->z);
1407  // xmlOut.addTextElementToParent("xyz_point", str, objectParent);
1408  // }
1409  // }
1410  }
1411  else if(
1412  requestType ==
1413  "getRootConfig") // ################################################################################################################
1414  {
1415  std::string path = CgiDataUtilities::postData(cgiIn, "RootConfigPath");
1416  __SUP_COUT__ << "path " << path << __E__;
1417 
1418  if(path.find("/" + PRE_MADE_ROOT_CFG_DIR + "/") ==
1419  0) // ROOT config path must start the path
1420  {
1421  path = std::string(ROOT_DISPLAY_CONFIG_PATH) + "/" +
1422  path.substr(PRE_MADE_ROOT_CFG_DIR.length() + 2);
1423  __SUP_COUT__ << "mod path " << path << __E__;
1424  }
1425 
1426  HttpXmlDocument cfgXml;
1427  if(cfgXml.loadXmlDocument(path))
1428  {
1429  xmlOut.addTextElementToData("status", "1");
1430  xmlOut.copyDataChildren(cfgXml); // copy file to output xml
1431  cfgXml.saveXmlDocument(path);
1432  }
1433  else
1434  xmlOut.addTextElementToData("status",
1435  "Failed. File to properly load config file.");
1436  }
1437  else if(
1438  requestType ==
1439  "rootAdminControls") // ################################################################################################################
1440  {
1441  // if(userPermissions < ROOT_VIEWER_PERMISSIONS_THRESHOLD)
1442  // {
1443  // __SUP_COUT__ << "Insufficient permissions for Root Viewer Admin
1444  // Controls: " << userPermissions << " < " << ROOT_VIEWER_PERMISSIONS_THRESHOLD <<
1445  // __E__;
1446  // xmlOut.addTextElementToData("status", "Failed. Insufficient user
1447  // permissions.");
1448  // }
1449  // else
1450  // {
1451  std::string cmd = cgiIn("cmd"); // possible commands are
1452  // mkdir
1453  // save
1454  // delete
1455 
1456  std::string path = CgiDataUtilities::postData(cgiIn, "path");
1457  std::string name = CgiDataUtilities::postData(cgiIn, "name");
1458  __SUP_COUT__ << "cmd " << cmd << __E__;
1459  __SUP_COUT__ << "path " << path << __E__;
1460  __SUP_COUT__ << "name " << name << __E__;
1461 
1462  if(path.find("/" + PRE_MADE_ROOT_CFG_DIR + "/") ==
1463  0) // ROOT config path must start the path
1464  {
1465  path = std::string(ROOT_DISPLAY_CONFIG_PATH) + "/" +
1466  path.substr(PRE_MADE_ROOT_CFG_DIR.length() + 2) + name;
1467  __SUP_COUT__ << "mod path " << path << __E__;
1468 
1469  if(cmd == "mkdir")
1470  {
1471  if(mkdir(path.c_str(),
1472  S_IRWXU | (S_IRGRP | S_IXGRP) |
1473  (S_IROTH | S_IXOTH))) // mode = drwx r-x r-x
1474  xmlOut.addTextElementToData("status",
1475  "Failed. Directory create rejected.");
1476  else
1477  xmlOut.addTextElementToData("status", "1"); // success
1478  }
1479  else if(cmd == "save")
1480  {
1481  path += PRE_MADE_ROOT_CFG_FILE_EXT; // add file extension
1482 
1483  bool useRunWildCard =
1484  atoi(CgiDataUtilities::postData(cgiIn, "useRunWildCard")
1485  .c_str()); // 0 or 1
1486  std::string config = CgiDataUtilities::postData(cgiIn, "config");
1487  __SUP_COUT__ << "config " << config << __E__;
1488  __SUP_COUT__ << "useRunWildCard " << useRunWildCard << __E__;
1489 
1490  // check if file already exists
1491  FILE* fp = fopen(path.c_str(), "r");
1492  if(fp)
1493  {
1494  fclose(fp);
1495  xmlOut.addTextElementToData("status", "Failed. File already exists.");
1496  __SUP_COUT__ << " Failed. File already exists." << __E__;
1497  }
1498  else
1499  {
1500  // dump to file
1501  // verify proper format through read back
1502  // if successfully loaded, re-save for formatting
1503 
1504  // dump to file
1505  fp = fopen(path.c_str(), "w");
1506  fputs(config.c_str(), fp);
1507  fclose(fp);
1508 
1509  // verify proper format through read back
1510  HttpXmlDocument cfgXml;
1511  if(cfgXml.loadXmlDocument(path))
1512  {
1513  // successfully loaded, re-save for formatting
1514  cfgXml.saveXmlDocument(path);
1515  xmlOut.addTextElementToData("status", "1"); // success
1516  }
1517  else // failed to load properly
1518  {
1519  xmlOut.addTextElementToData(
1520  "status", "Failed. Fatal. Improper file format.");
1521  if(remove(path.c_str()) != 0)
1522  __SUP_COUT__ << "Failed. Could not remove poorly formed Root "
1523  "config file!"
1524  << __E__;
1525  }
1526  }
1527  }
1528  else if(cmd == "delete")
1529  {
1530  // guess first directory and then file
1531  if(rmdir(path.c_str()) == 0 ||
1532  remove((path + PRE_MADE_ROOT_CFG_FILE_EXT).c_str()) == 0)
1533  xmlOut.addTextElementToData("status", "1"); // success
1534  else
1535  xmlOut.addTextElementToData("status",
1536  "Failed. Target could not be deleted.");
1537  }
1538  else
1539  xmlOut.addTextElementToData("status", "Failed. Unrecognized command.");
1540  }
1541  else
1542  xmlOut.addTextElementToData("status", "Failed. Invalid path.");
1543 
1544  //}
1545  }
1546  else if(
1547  requestType ==
1548  "getMeDirs") // ################################################################################################################
1549  {
1550  xmlOut.setDarioStyle(true); // workaround for XML formatting....
1551  std::string fSystemPath = std::string(ROOT_BROWSER_PATH) + "/";
1552  std::string fRootPath = CgiDataUtilities::postData(cgiIn, "Path");
1553  boost::regex re("%2F");
1554  fRootPath = boost::regex_replace(fRootPath, re, "/");
1555  std::string fullPath = fSystemPath + fRootPath;
1556  // fFoldersPath_ = "pippo" ;
1557  STDLINE(std::string("Begin: fSystemPath = ") + fSystemPath, ACWhite);
1558  STDLINE(std::string("Begin: fRootPath = ") + fRootPath, ACWhite);
1559  STDLINE(std::string("Begin: fullPath = ") + fullPath, ACWhite);
1560  // STDLINE(std::string("Begin: fFoldersPath = ")+fFoldersPath_,ACCyan ) ;
1561 
1562  xmlOut.setRootPath(fRootPath);
1563  xmlOut.makeDirectoryBinaryTree(fSystemPath, fRootPath, 0, NULL);
1564  std::ostringstream* out = new std::ostringstream();
1565  xmlOut.outputXmlDocument((std::ostringstream*)out, true);
1566  }
1567  else if(
1568  requestType ==
1569  "getMeRootFile") // ################################################################################################################
1570  {
1571  xmlOut.setDarioStyle(true); // workaround for XML formatting....
1572  std::string fSystemPath = std::string(ROOT_BROWSER_PATH) + "/";
1573  std::string fRootPath = CgiDataUtilities::postData(cgiIn, "fRootPath");
1574  std::string fFoldersPath = CgiDataUtilities::postData(cgiIn, "fFoldersPath");
1575  std::string fHistName = CgiDataUtilities::postData(cgiIn, "fHistName");
1576  std::string fRFoldersPath = CgiDataUtilities::postData(cgiIn, "fRFoldersPath");
1577  std::string fFileName = CgiDataUtilities::postData(cgiIn, "fFileName");
1578  boost::regex re("%2F");
1579  fRootPath = boost::regex_replace(fRootPath, re, "/");
1580  fFoldersPath = boost::regex_replace(fFoldersPath, re, "/");
1581  // STDLINE(std::string("fSystemPath : ")+fSystemPath ,ACCyan);
1582  // STDLINE(std::string("fRootPath : ")+fRootPath ,ACCyan);
1583  // STDLINE(std::string("fFoldersPath : ")+fFoldersPath ,ACCyan);
1584  // STDLINE(std::string("fHistName : ")+fHistName ,ACCyan);
1585  // STDLINE(std::string("fRFoldersPath: ")+fRFoldersPath,ACCyan);
1586  // STDLINE(std::string("fFileName : ")+fFileName ,ACCyan);
1587  RootFileExplorer* theExplorer = new RootFileExplorer(
1588  fSystemPath, fRootPath, fFoldersPath, fHistName, fRFoldersPath, fFileName);
1589  xmlOut.setDocument(theExplorer->initialize(false));
1590  // std::ostringstream* out ;
1591  // xmlOut.outputXmlDocument((std::ostringstream*) out, true);
1592  }
1593  // else if(
1594  // requestType ==
1595  // "getMeLIVE-DQMFile")
1596  // //################################################################################################################
1597  // {
1598  // xmlOut.setDarioStyle(true); // workaround for XML formatting....
1599  // std::string fSystemPath = std::string(ROOT_BROWSER_PATH) + "/";
1600  // std::string fRootPath = CgiDataUtilities::postData(cgiIn, "fRootPath");
1601  // std::string fFoldersPath = CgiDataUtilities::postData(cgiIn, "fFoldersPath");
1602  // std::string fHistName = CgiDataUtilities::postData(cgiIn, "fHistName");
1603  // std::string fRFoldersPath = CgiDataUtilities::postData(cgiIn, "fRFoldersPath");
1604  // std::string fFileName = CgiDataUtilities::postData(cgiIn, "fFileName");
1605  // STDLINE(std::string("fSystemPath : ") + fSystemPath, ACCyan);
1606  // STDLINE(std::string("fRootPath : ") + fRootPath, ACCyan);
1607  // STDLINE(std::string("fFoldersPath : ") + fFoldersPath, ACCyan);
1608  // STDLINE(std::string("fHistName : ") + fHistName, ACCyan);
1609  // STDLINE(std::string("fRFoldersPath: ") + fRFoldersPath, ACCyan);
1610  // STDLINE(std::string("fFileName : ") + fFileName, ACCyan);
1611  // boost::regex re("%2F");
1612  // fRootPath = boost::regex_replace(fRootPath, re, "/");
1613  // fFoldersPath = boost::regex_replace(fFoldersPath, re, "/");
1614 
1615  // TFile* rootFile;
1616  // STDLINE("Getting LiveDQMHistos", ACGreen);
1617  // if(theDataManager_->getLiveDQMHistos() != nullptr)
1618  // {
1619  // STDLINE("Selecting LIVE_DQM.root", ACCyan);
1620  // rootFile = theDataManager_->getLiveDQMHistos()->getFile();
1621  // fRootPath = "LIVE_DQM.root";
1622  // }
1623  // else
1624  // {
1625  // STDLINE(string("fRootPath: ") + fRootPath, ACGreen);
1626  // rootFile = TFile::Open(fRootPath.c_str());
1627  // }
1628  // string cmd = string("ls -la ") + fRootPath;
1629  // system(cmd.c_str());
1630  // // STDLINE(string("before regexp fRootPath: ")+fRootPath,ACGreen) ;
1631  // // fRootPath = rootFile->GetName() ; // Bisogna strippare via il full path!!!
1632  // // boost::regex regg(fSystemPath.c_str()) ;
1633  // // fRootPath = boost::regex_replace(fRootPath,regg,"/") ; // Dario: should be
1634  // // transparent for Ryan's purposes but required by Extjs STDLINE(string("after
1635  // // regexp fRootPath: ")+fRootPath,ACGreen) ;
1636  // STDLINE(std::string("fSystemPath : ") + fSystemPath, ACCyan);
1637  // STDLINE(std::string("fRootPath : ") + fRootPath, ACCyan);
1638  // STDLINE(std::string("fFoldersPath : ") + fFoldersPath, ACCyan);
1639  // STDLINE(std::string("fHistName : ") + fHistName, ACCyan);
1640  // STDLINE(std::string("fRFoldersPath: ") + fRFoldersPath, ACCyan);
1641  // STDLINE(std::string("fFileName : ") + fFileName, ACCyan);
1642  // RootFileExplorer* theExplorer = new RootFileExplorer(fSystemPath,
1643  // fRootPath,
1644  // fFoldersPath,
1645  // fHistName,
1646  // fRFoldersPath,
1647  // fFileName,
1648  // rootFile);
1649  // xmlOut.setDocument(theExplorer->initialize(true));
1650  // // std::ostringstream* out ;
1651  // // xmlOut.outputXmlDocument((std::ostringstream*) out, true);
1652  // }
1653  else if(
1654  requestType ==
1655  "saveConfiguration") // ################################################################################################################
1656  {
1657  std::string configPayload = CgiDataUtilities::postData(cgiIn, "configPayload");
1658  STDLINE("configPayload: ", ACRed);
1659  STDLINE(configPayload, ACYellow);
1660 
1661  fstream outFile;
1662  outFile.open("/tmp/configPayload.json", ios::out | ios::app);
1663  outFile << configPayload << endl;
1664  outFile.close();
1665  }
1666  else if(
1667  requestType ==
1668  "getConfiguration") // ################################################################################################################
1669  {
1670  std::string configPayload = CgiDataUtilities::postData(cgiIn, "configPayload");
1671  std::string JSONPayLoad = "";
1672  std::string line = "";
1673 
1674  ifstream JSONFile("/tmp/configPayload.json");
1675 
1676  if(JSONFile.is_open())
1677  {
1678  while(getline(JSONFile, line))
1679  {
1680  JSONPayLoad += line;
1681  }
1682  JSONFile.close();
1683  }
1684 
1685  xmlOut.addTextElementToData("JSONPayLoad", JSONPayLoad);
1686  // std::ostringstream* out ;
1687  // xmlOut.outputXmlDocument((std::ostringstream*) out, true);
1688  }
1689  else if(
1690  requestType ==
1691  "getState") // ################################################################################################################
1692  {
1693  std::string fsmName = theStateMachine_.getCurrentStateName();
1694  bool in_transition = theStateMachine_.isInTransition();
1695 
1696  xmlOut.addTextElementToData("current_state", fsmName);
1697  xmlOut.addTextElementToData("in_transition", in_transition ? "1" : "0");
1698  }
1699  else
1700  {
1701  __SUP_SS__ << "requestType Request, " << requestType
1702  << ", not recognized by the Visual Supervisor (was it intended for "
1703  "another Supervisor?)."
1704  << __E__;
1705  __SUP_SS_THROW__;
1706  }
1707 
1708  if(theDataManager_ != nullptr)
1709  theDataManager_->setDoNotStop(false);
1710 
1711 } //end request()
static std::string postData(cgicc::Cgicc &cgi, const std::string &needle)
static std::string getData(cgicc::Cgicc &cgi, const std::string &needle)
bool isDisconnected(void) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
const std::string & getValueAsString(bool returnLinkTableValue=false) const
WebUsers::permissionLevel_t getSupervisorPropertyUserPermissionsThreshold(const std::string &requestType)
virtual void transitionHalting(toolbox::Event::Reference event)
static void deleteInstance(std::string instanceUID)
void copyDataChildren(HttpXmlDocument &document)
bool loadXmlDocument(const std::string &filePath)
void outputXmlDocument(std::ostringstream *out, bool dispStdOut=false, bool allowWhiteSpace=false, bool printErrors=false)
const std::vector< DQMHistosBase * > & getLiveDQMs(void)
virtual void setSupervisorPropertyDefaults(void) override
virtual void forceSupervisorPropertyValues(void) override
virtual void transitionConfiguring(toolbox::Event::Reference e) override
virtual void request(const std::string &requestType, cgicc::Cgicc &cgiIn, HttpXmlDocument &xmlOut, const WebUsers::RequestUserInfo &userInfo) override
xercesc::DOMElement * addTextElementToParent(const std::string &childName, const std::string &childText, xercesc::DOMElement *parent)
void setDarioStyle(bool darioStyle)
void saveXmlDocument(const std::string &filePath)
void INIT_MF(const char *name)
static std::string binaryStringToHexString(const void *binaryBuffer, unsigned int numberOfBytes, const std::string &resultPreamble="", const std::string &resultDelimiter="")