otsdaq  v1_01_04
 All Classes Namespaces Functions
Supervisor.cc
1 #include "otsdaq-core/Supervisor/Supervisor.h"
2 #include "otsdaq-core/MessageFacility/MessageFacility.h"
3 #include "otsdaq-core/Macros/CoutHeaderMacros.h"
4 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
5 #include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h"
6 #include "otsdaq-core/SOAPUtilities/SOAPUtilities.h"
7 #include "otsdaq-core/SOAPUtilities/SOAPCommand.h"
8 
9 #include "otsdaq-core/WorkLoopManager/WorkLoopManager.h"
10 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h"
11 #include "otsdaq-core/ConfigurationInterface/ConfigurationManagerRW.h"
12 #include "otsdaq-core/ConfigurationPluginDataFormats/XDAQContextConfiguration.h"
13 #include <cgicc/HTMLClasses.h>
14 #include <cgicc/HTTPCookie.h>
15 #include <cgicc/HTMLDoctype.h>
16 #include <cgicc/HTTPHeader.h>
17 #include <xgi/Utils.h>
18 
19 #include <xoap/Method.h>
20 #include <xdaq/NamespaceURI.h>
21 #include <toolbox/task/WorkLoopFactory.h>
22 #include <toolbox/fsm/FailedEvent.h>
23 
24 #include <fstream>
25 #include <thread> // std::this_thread::sleep_for
26 #include <chrono> // std::chrono::seconds
27 #include <sys/stat.h> //for mkdir
28 
29 using namespace ots;
30 
31 
32 #define ICON_FILE_NAME std::string(getenv("SERVICE_DATA_PATH")) + "/OtsWizardData/iconList.dat"
33 #define RUN_NUMBER_PATH std::string(getenv("SERVICE_DATA_PATH")) + "/RunNumber/"
34 #define RUN_NUMBER_FILE_NAME "NextRunNumber.txt"
35 #define FSM_LAST_GROUP_ALIAS_PATH std::string(getenv("SERVICE_DATA_PATH")) + "/RunControlData/"
36 #define FSM_LAST_GROUP_ALIAS_FILE_START std::string("FSMLastGroupAlias-")
37 #define FSM_USERS_PREFERENCES_FILETYPE "pref"
38 
39 
40 #undef __MF_SUBJECT__
41 #define __MF_SUBJECT__ "GatewaySupervisor"
42 
43 
44 XDAQ_INSTANTIATOR_IMPL(Supervisor)
45 
46 
47 //========================================================================================================================
48 Supervisor::Supervisor(xdaq::ApplicationStub * s) throw (xdaq::exception::Exception)
49 :xdaq::Application (s)
50 ,SOAPMessenger (this)
52 ,outputDir_ ("")
53 ,theConfigurationManager_ (new ConfigurationManager)
54 //,theConfigurationGroupKey_ (nullptr)
55 ,stateMachineWorkLoopManager_ (toolbox::task::bind(this, &Supervisor::stateMachineThread,"StateMachine"))
56 ,stateMachineSemaphore_ (toolbox::BSem::FULL)
57 ,infoRequestWorkLoopManager_ (toolbox::task::bind(this, &Supervisor::infoRequestThread, "InfoRequest"))
58 ,infoRequestSemaphore_ (toolbox::BSem::FULL)
59 ,activeStateMachineName_ ("")
60 ,theIterator_ (this)
61 ,counterTest_ (0)
62 {
63  INIT_MF("Supervisor");
64  __COUT__ << std::endl;
65 
66  //attempt to make directory structure (just in case)
67  mkdir((FSM_LAST_GROUP_ALIAS_PATH).c_str(), 0755);
68  mkdir((RUN_NUMBER_PATH).c_str(), 0755);
69 
70  securityType_ = theWebUsers_.getSecurity();
71 
72  __COUT__ << "Security: " << securityType_ << std::endl;
73 
74  xgi::bind(this, &Supervisor::Default, "Default");
75  xgi::bind(this, &Supervisor::loginRequest, "LoginRequest");
76  xgi::bind(this, &Supervisor::request, "Request");
77  xgi::bind(this, &Supervisor::stateMachineXgiHandler, "StateMachineXgiHandler");
78  xgi::bind(this, &Supervisor::infoRequestHandler, "InfoRequestHandler");
79  xgi::bind(this, &Supervisor::infoRequestResultHandler, "InfoRequestResultHandler");
80  xgi::bind(this, &Supervisor::tooltipRequest, "TooltipRequest");
81 
82  xoap::bind(this, &Supervisor::supervisorCookieCheck, "SupervisorCookieCheck", XDAQ_NS_URI);
83  xoap::bind(this, &Supervisor::supervisorGetActiveUsers, "SupervisorGetActiveUsers", XDAQ_NS_URI);
84  xoap::bind(this, &Supervisor::supervisorSystemMessage, "SupervisorSystemMessage", XDAQ_NS_URI);
85  xoap::bind(this, &Supervisor::supervisorGetUserInfo, "SupervisorGetUserInfo", XDAQ_NS_URI);
86  xoap::bind(this, &Supervisor::supervisorSystemLogbookEntry, "SupervisorSystemLogbookEntry", XDAQ_NS_URI);
87  xoap::bind(this, &Supervisor::supervisorLastConfigGroupRequest, "SupervisorLastConfigGroupRequest", XDAQ_NS_URI);
88 
89 
90  //old:
91  //I always load all configuration even the one that is not related to the particular FEW/FER,
92  //so I can load it once and is good for all applications I am scared about threads so I comment it out!
93  //theConfigurationManager_ = Singleton<ConfigurationManager>::getInstance();
94 
95  init();
96 
97  //Note: print out handled by StartOTS.sh now
98  //std::thread([](Supervisor *supervisorPtr){ Supervisor::URLDisplayThread(supervisorPtr); }, this).detach();
99 }
100 
101 //========================================================================================================================
102 // TODO: Lore needs to detect program quit through killall or ctrl+c so that Logbook entry is made when ots is halted
103 Supervisor::~Supervisor(void)
104 {
105  delete theConfigurationManager_;
106  makeSystemLogbookEntry("ots halted.");
107 }
108 
109 //========================================================================================================================
110 void Supervisor::init(void)
111 {
112  //This can be done in the constructor because when you start xdaq it loads the configuration that can't be changed while running!
113  theSupervisorDescriptorInfo_.init(getApplicationContext());
114  theSupervisorsInfo_.init(theSupervisorDescriptorInfo_);
115 
116  supervisorGuiHasBeenLoaded_ = false;
117 
118  const XDAQContextConfiguration* contextConfiguration = theConfigurationManager_->__GET_CONFIG__(XDAQContextConfiguration);
119 
120  supervisorContextUID_ = contextConfiguration->getContextUID(
121  getApplicationContext()->getContextDescriptor()->getURL()
122  );
123  __COUT__ << "Context UID:" << supervisorContextUID_ << std::endl;
124 
125  supervisorApplicationUID_ = contextConfiguration->getApplicationUID(
126  getApplicationContext()->getContextDescriptor()->getURL(),
127  getApplicationDescriptor()->getLocalId()
128  );
129 
130  __COUT__ << "Application UID:" << supervisorApplicationUID_ << std::endl;
131 
132  ConfigurationTree configLinkNode = theConfigurationManager_->getSupervisorConfigurationNode(
133  supervisorContextUID_, supervisorApplicationUID_);
134  // getNode(
135  // "/XDAQContextConfiguration/" + supervisorContextUID_ +
136  // "/LinkToApplicationConfiguration/" + supervisorApplicationUID_ +
137  // "/LinkToSupervisorConfiguration");
138  std::string supervisorUID;
139  if(!configLinkNode.isDisconnected())
140  supervisorUID = configLinkNode.getValue();
141  else
142  supervisorUID = ViewColumnInfo::DATATYPE_LINK_DEFAULT;
143 
144  __COUT__ << "Supervisor UID:" << supervisorUID << std::endl;
145 }
146 
147 //========================================================================================================================
148 void Supervisor::URLDisplayThread(Supervisor *supervisorPtr)
149 {
150  INIT_MF("Supervisor");
151  //_Exit(0); //Uncomment to stop print out
152  // child process
153  int i = 0;
154  for (; i < 5; ++i)
155  {
156  std::this_thread::sleep_for (std::chrono::seconds(2));
157  std:: cout << __COUT_HDR_FL__ << "\n*********************************************************************" << std::endl;
158  std:: cout << __COUT_HDR_FL__ << "\n\n"
159  << supervisorPtr->getApplicationContext()->getContextDescriptor()->getURL() //<<// ":" // getenv("SUPERVISOR_SERVER") << ":"
160  //<< this->getApplicationDescriptor()-> getenv("PORT") <<
161  << "/urn:xdaq-application:lid="
162  << supervisorPtr->getApplicationDescriptor()->getLocalId() << "/"
163  << "\n" << std::endl;
164  std:: cout << __COUT_HDR_FL__ << "\n*********************************************************************" << std::endl;
165  }
166 }
167 
168 //========================================================================================================================
169 //makeSystemLogbookEntry
170 // makes a logbook entry into the current active experiments logbook for a system event
171 // escape entryText to make it html/xml safe!!
173 void Supervisor::makeSystemLogbookEntry(std::string entryText)
174 {
175  __COUT__ << "Making System Logbook Entry: " << entryText << std::endl;
176 
177  //make sure Logbook has been configured into xdaq context
178  if(!theSupervisorDescriptorInfo_.getLogbookDescriptor())
179  {
180  __COUT__ << "Just kidding... Logbook Descriptor not found." << std:: endl;
181  return;
182  }
183 
184  //__COUT__ << "before: " << entryText << std::endl;
185  { //input entryText
186  std::string replace[] =
187  {"\"", "'", "&", "<", ">", "\n", " "};
188  std::string with[] =
189  {"%22","%27", "%26", "%3C", "%3E", "%0A%0D", "%20%20"};
190 
191  int numOfKeys = 7;
192 
193  size_t f;
194  for(int i=0;i<numOfKeys;++i)
195  {
196  while((f=entryText.find(replace[i])) != std::string::npos)
197  {
198  entryText = entryText.substr(0,f) + with[i] + entryText.substr(f+replace[i].length());
199  //__COUT__ << "found " << " " << entryText << std::endl;
200  }
201  }
202  }
203  //__COUT__ << "after: " << entryText << std::endl;
204 
205  SOAPParameters parameters("EntryText",entryText);
206  //SOAPParametersV parameters(1);
207  //parameters[0].setName("EntryText"); parameters[0].setValue(entryText);
208 
209  xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply(theSupervisorDescriptorInfo_.getLogbookDescriptor(), "MakeSystemLogbookEntry",parameters);
210 
211  SOAPParameters retParameters("Status");
212  //SOAPParametersV retParameters(1);
213  //retParameters[0].setName("Status");
214  receive(retMsg, retParameters);
215 
216  __COUT__ << "Returned Status: " << retParameters.getValue("Status") << std::endl;//retParameters[0].getValue() << std::endl << std::endl;
217 
218 }
219 
220 //========================================================================================================================
221 void Supervisor::Default(xgi::Input* in, xgi::Output* out)
222 throw (xgi::exception::Exception)
223 {
224  //
225  if (!supervisorGuiHasBeenLoaded_ && (supervisorGuiHasBeenLoaded_ = true)) //make system logbook entry that ots has been started
226  makeSystemLogbookEntry("ots started.");
227 
228  *out <<
229  "<!DOCTYPE HTML><html lang='en'><head><title>ots</title>" <<
230  //show ots icon
231  // from http://www.favicon-generator.org/
232  "<link rel='apple-touch-icon' sizes='57x57' href='/WebPath/images/otsdaqIcons/apple-icon-57x57.png'>\
233  <link rel='apple-touch-icon' sizes='60x60' href='/WebPath/images/otsdaqIcons/apple-icon-60x60.png'>\
234  <link rel='apple-touch-icon' sizes='72x72' href='/WebPath/images/otsdaqIcons/apple-icon-72x72.png'>\
235  <link rel='apple-touch-icon' sizes='76x76' href='/WebPath/images/otsdaqIcons/apple-icon-76x76.png'>\
236  <link rel='apple-touch-icon' sizes='114x114' href='/WebPath/images/otsdaqIcons/apple-icon-114x114.png'>\
237  <link rel='apple-touch-icon' sizes='120x120' href='/WebPath/images/otsdaqIcons/apple-icon-120x120.png'>\
238  <link rel='apple-touch-icon' sizes='144x144' href='/WebPath/images/otsdaqIcons/apple-icon-144x144.png'>\
239  <link rel='apple-touch-icon' sizes='152x152' href='/WebPath/images/otsdaqIcons/apple-icon-152x152.png'>\
240  <link rel='apple-touch-icon' sizes='180x180' href='/WebPath/images/otsdaqIcons/apple-icon-180x180.png'>\
241  <link rel='icon' type='image/png' sizes='192x192' href='/WebPath/images/otsdaqIcons/android-icon-192x192.png'>\
242  <link rel='icon' type='image/png' sizes='32x32' href='/WebPath/images/otsdaqIcons/favicon-32x32.png'>\
243  <link rel='icon' type='image/png' sizes='96x96' href='/WebPath/images/otsdaqIcons/favicon-96x96.png'>\
244  <link rel='icon' type='image/png' sizes='16x16' href='/WebPath/images/otsdaqIcons/favicon-16x16.png'>\
245  <link rel='manifest' href='/WebPath/images/otsdaqIcons/manifest.json'>\
246  <meta name='msapplication-TileColor' content='#ffffff'>\
247  <meta name='msapplication-TileImage' content='/ms-icon-144x144.png'>\
248  <meta name='theme-color' content='#ffffff'>" <<
249  //end show ots icon
250  "</head>" <<
251  "<frameset col='100%' row='100%'>" <<
252  "<frame src='/WebPath/html/Supervisor.html?urn=" <<
253  this->getApplicationDescriptor()->getLocalId() << "=securityType=" <<
254  securityType_ << "'></frameset></html>";
255 }
256 
257 
258 
259 //========================================================================================================================
260 void Supervisor::stateMachineXgiHandler(xgi::Input* in, xgi::Output* out)
261 throw (xgi::exception::Exception)
262 {
263  //for simplicity assume all commands should be mutually exclusive with iterator thread state machine accesses (really should just be careful with RunControlStateMachine access)
264  if(VERBOSE_MUTEX) __COUT__ << "Waiting for FSM access" << std::endl;
265  std::lock_guard<std::mutex> lock(stateMachineAccessMutex_);
266  if(VERBOSE_MUTEX) __COUT__ << "Have FSM access" << std::endl;
267 
268  cgicc::Cgicc cgi(in);
269 
270  uint8_t userPermissions;
271  uint64_t uid;
272  std::string userWithLock;
273  std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode");
274  if (!theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, &userPermissions,
275  &uid, "0", 1, &userWithLock))
276  {
277  *out << cookieCode;
278  return;
279  }
280 
281  std::string command = CgiDataUtilities::getData(cgi, "StateMachine");
282 
283  //**** start LOCK GATEWAY CODE ***//
284  std::string username = "";
285  username = theWebUsers_.getUsersUsername(uid);
286  if (userWithLock != "" && userWithLock != username)
287  {
288  *out << WebUsers::REQ_USER_LOCKOUT_RESPONSE;
289  __COUT__ << "User " << username << " is locked out. " << userWithLock << " has lock." << std::endl;
290  return;
291  }
292  //**** end LOCK GATEWAY CODE ***//
293 
294  HttpXmlDocument xmldoc(cookieCode);
295  std::string fsmName = CgiDataUtilities::getData(cgi, "fsmName");
296  std::string fsmWindowName = CgiDataUtilities::getData(cgi, "fsmWindowName");
297  fsmWindowName = CgiDataUtilities::decodeURIComponent(fsmWindowName);
298  std::string currentState = theStateMachine_.getCurrentStateName();
299 
300  //Do not allow transition while in transition
301  if (theStateMachine_.isInTransition())
302  {
303  __SS__ << "Error - Can not accept request because the State Machine is already in transition!" << std::endl;
304  __COUT_ERR__ << "\n" << ss.str();
305 
306  xmldoc.addTextElementToData("state_tranisition_attempted", "0"); //indicate to GUI transition NOT attempted
307  xmldoc.addTextElementToData("state_tranisition_attempted_err",
308  ss.str()); //indicate to GUI transition NOT attempted
309  xmldoc.outputXmlDocument((std::ostringstream*) out, false, true);
310  return;
311  }
312 
313  __COUT__ << "Check for Handled by theIterator_" << std::endl;
314 
315  //check if Iterator should handle
316  if((activeStateMachineWindowName_ == "" ||
317  activeStateMachineWindowName_ == "iterator") &&
318  theIterator_.handleCommandRequest(xmldoc,command,fsmWindowName))
319  {
320  __COUT__ << "Handled by theIterator_" << std::endl;
321  xmldoc.outputXmlDocument((std::ostringstream*) out, false);
322  return;
323  }
324 
325 
327  //Validate FSM name
328  // if fsm name != active fsm name
329  // only allow, if current state is halted or init
330  // take active fsm name when configured
331  // else, allow
332  if(activeStateMachineName_ != "" &&
333  activeStateMachineName_ != fsmName)
334  {
335  __COUT__ << "currentState = " <<
336  currentState << std::endl;
337  if(currentState != "Halted" &&
338  currentState != "Initial")
339  {
340  //illegal for this FSM name to attempt transition
341 
342  __SS__ << "Error - Can not accept request because the State Machine " <<
343  "with window name '" <<
344  activeStateMachineWindowName_ << "' (UID: " <<
345  activeStateMachineName_ << ") "
346  "is currently " <<
347  "in control of State Machine progress. ";
348  ss << "\n\nIn order for this State Machine with window name '" <<
349  fsmWindowName << "' (UID: " << fsmName << ") "
350  "to control progress, please transition to Halted using the active " <<
351  "State Machine '" << activeStateMachineWindowName_ << ".'" << std::endl;
352  __COUT_ERR__ << "\n" << ss.str();
353 
354  xmldoc.addTextElementToData("state_tranisition_attempted", "0"); //indicate to GUI transition NOT attempted
355  xmldoc.addTextElementToData("state_tranisition_attempted_err",
356  ss.str()); //indicate to GUI transition NOT attempted
357  xmldoc.outputXmlDocument((std::ostringstream*) out, false, true);
358  return;
359  }
360  else //clear active state machine
361  {
362  activeStateMachineName_ = "";
363  activeStateMachineWindowName_ = "";
364  }
365  }
366 
367 
368 
369 
370  //At this point, attempting transition!
371 
372  std::vector<std::string> parameters;
373  if(command == "Configure")
374  parameters.push_back(CgiDataUtilities::postData(cgi, "ConfigurationAlias"));
375  attemptStateMachineTransition(&xmldoc,out,command,fsmName,fsmWindowName,
376  username,parameters);
377 }
378 
379 std::string Supervisor::attemptStateMachineTransition(
380  HttpXmlDocument* xmldoc, std::ostringstream* out,
381  const std::string& command,
382  const std::string& fsmName, const std::string& fsmWindowName,
383  const std::string& username,
384  const std::vector<std::string>& commandParameters)
385 {
386  std::string errorStr = "";
387 
388  std::string currentState = theStateMachine_.getCurrentStateName();
389  __COUT__ << "State Machine command = " << command << std::endl;
390  __COUT__ << "fsmName = " << fsmName << std::endl;
391  __COUT__ << "fsmWindowName = " << fsmWindowName << std::endl;
392  __COUT__ << "activeStateMachineName_ = " << activeStateMachineName_ << std::endl;
393 
394  SOAPParameters parameters;
395  if (command == "Configure")
396  {
397  if(currentState != "Halted") //check if out of sync command
398  {
399  __SS__ << "Error - Can only transition to Configured if the current " <<
400  "state is Halted. Perhaps your state machine is out of sync." <<
401  std::endl;
402  __COUT_ERR__ << "\n" << ss.str();
403  errorStr = ss.str();
404 
405  if(xmldoc) xmldoc->addTextElementToData("state_tranisition_attempted", "0"); //indicate to GUI transition NOT attempted
406  if(xmldoc) xmldoc->addTextElementToData("state_tranisition_attempted_err",
407  ss.str()); //indicate to GUI transition NOT attempted
408  if(out) xmldoc->outputXmlDocument((std::ostringstream*) out, false, true);
409 
410  return errorStr;
411  }
412 
413  //NOTE Original name of the configuration key
414  //parameters.addParameter("RUN_KEY",CgiDataUtilities::postData(cgi,"ConfigurationAlias"));
415  if(!commandParameters.size())
416  {
417  __SS__ << "Error - Can only transition to Configured if a Configuration Alias parameter is provided." <<
418  std::endl;
419  __COUT_ERR__ << "\n" << ss.str();
420  errorStr = ss.str();
421 
422  if(xmldoc) xmldoc->addTextElementToData("state_tranisition_attempted", "0"); //indicate to GUI transition NOT attempted
423  if(xmldoc) xmldoc->addTextElementToData("state_tranisition_attempted_err",
424  ss.str()); //indicate to GUI transition NOT attempted
425  if(out) xmldoc->outputXmlDocument((std::ostringstream*) out, false, true);
426 
427  return errorStr;
428  }
429 
430  parameters.addParameter("ConfigurationAlias",
431  commandParameters[0]);
432 
433  std::string configurationAlias = parameters.getValue("ConfigurationAlias");
434  __COUT__ << "Configure --> Name: ConfigurationAlias Value: " <<
435  configurationAlias << std::endl;
436 
437  //save last used config alias
438  std::string fn = FSM_LAST_GROUP_ALIAS_PATH + FSM_LAST_GROUP_ALIAS_FILE_START +
439  username + "." + FSM_USERS_PREFERENCES_FILETYPE;
440 
441  __COUT__ << "Save FSM preferences: " << fn << std::endl;
442  FILE *fp = fopen(fn.c_str(),"w");
443  if(!fp)
444  {
445  __SS__ << ("Could not open file: " + fn) << std::endl;
446  __COUT_ERR__ << ss.str();
447  throw std::runtime_error(ss.str());
448  }
449  fprintf(fp,"FSM_last_configuration_alias %s",configurationAlias.c_str());
450  fclose(fp);
451 
452  activeStateMachineName_ = fsmName;
453  activeStateMachineWindowName_ = fsmWindowName;
454  }
455  else if (command == "Start")
456  {
457  if(currentState != "Configured") //check if out of sync command
458  {
459  __SS__ << "Error - Can only transition to Configured if the current " <<
460  "state is Halted. Perhaps your state machine is out of sync. " <<
461  "(Likely the server was restarted or another user changed the state)" <<
462  std::endl;
463  __COUT_ERR__ << "\n" << ss.str();
464  errorStr = ss.str();
465 
466  if(xmldoc) xmldoc->addTextElementToData("state_tranisition_attempted", "0"); //indicate to GUI transition NOT attempted
467  if(xmldoc) xmldoc->addTextElementToData("state_tranisition_attempted_err",
468  ss.str()); //indicate to GUI transition NOT attempted
469  if(out) xmldoc->outputXmlDocument((std::ostringstream*) out, false, true);
470 
471  return errorStr;
472  }
473 
474  unsigned int runNumber = getNextRunNumber();
475  parameters.addParameter("RunNumber", runNumber);
476  setNextRunNumber(++runNumber);
477  }
478 
479  xoap::MessageReference message = SOAPUtilities::makeSOAPMessageReference(
480  command, parameters);
481  //Maybe we return an acknowledgment that the message has been received and processed
482  xoap::MessageReference reply = stateMachineXoapHandler(message);
483  //stateMachineWorkLoopManager_.removeProcessedRequests();
484  //stateMachineWorkLoopManager_.processRequest(message);
485 
486  if(xmldoc) xmldoc->addTextElementToData("state_tranisition_attempted", "1"); //indicate to GUI transition attempted
487  if(out) xmldoc->outputXmlDocument((std::ostringstream*) out, false);
488  __COUT__ << "FSM state transition launched!" << std::endl;
489 
490  return errorStr;
491 }
492 
493 //========================================================================================================================
494 void Supervisor::stateMachineResultXgiHandler(xgi::Input* in, xgi::Output* out)
495 throw (xgi::exception::Exception)
496 {
497  cgicc::Cgicc cgi(in);
498  __COUT__ << "Xgi Request!" << std::endl;
499 
500  uint8_t userPermissions; // uint64_t uid;
501  std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode");
502  if (!theWebUsers_.cookieCodeIsActiveForRequest(cookieCode,
503  &userPermissions))
504  {
505  *out << cookieCode;
506  return;
507  }
508 
509  HttpXmlDocument xmldoc(cookieCode);
510 
511  std::string command = CgiDataUtilities::getData(cgi, "StateMachine");
512 
513  SOAPParameters parameters;
514  /*
515  //FIXME I don't think that there should be this if statement and I guess it has been copied from the stateMachineXgiHandler method
516  if (command == "Configure")
517 
518 {
519  parameters.addParameter("RUN_KEY", CgiDataUtilities::postData(cgi, "ConfigurationAlias"));
520  __COUT__ << "Configure --> Name: RUN_KEY Value: " << parameters.getValue("RUN_KEY") << std::endl;
521  }
522  else if (command == "Start")
523 
524 {
525  unsigned int runNumber = getNextRunNumber();
526  std::stringstream runNumberStream;
527  runNumberStream << runNumber;
528  parameters.addParameter("RUN_NUMBER", runNumberStream.str().c_str());
529  setNextRunNumber(++runNumber);
530  }
531  */
532  xoap::MessageReference message = SOAPUtilities::makeSOAPMessageReference(
533  CgiDataUtilities::getData(cgi, "StateMachine"), parameters);
534  //Maybe we return an aknowledgment that the message has been received and processed
535  xoap::MessageReference reply = stateMachineResultXoapHandler(message);
536  //stateMachineWorkLoopManager_.removeProcessedRequests();
537  //stateMachineWorkLoopManager_.processRequest(message);
538  //xmldoc.outputXmlDocument((ostringstream*)out,false);
539  __COUT__ << "Done - Xgi Request!" << std::endl;
540 }
541 
542 //========================================================================================================================
543 xoap::MessageReference Supervisor::stateMachineXoapHandler(xoap::MessageReference message)
544 throw (xoap::exception::Exception)
545 {
546  __COUT__ << "Soap Handler!" << std::endl;
547  stateMachineWorkLoopManager_.removeProcessedRequests();
548  stateMachineWorkLoopManager_.processRequest(message);
549  __COUT__ << "Done - Soap Handler!" << std::endl;
550  return message;
551 }
552 
553 //========================================================================================================================
554 xoap::MessageReference Supervisor::stateMachineResultXoapHandler(
555  xoap::MessageReference message)
556 throw (xoap::exception::Exception)
557 {
558  __COUT__ << "Soap Handler!" << std::endl;
559  //stateMachineWorkLoopManager_.removeProcessedRequests();
560  //stateMachineWorkLoopManager_.processRequest(message);
561  __COUT__ << "Done - Soap Handler!" << std::endl;
562  return message;
563 }
564 
565 //========================================================================================================================
566 bool Supervisor::stateMachineThread(toolbox::task::WorkLoop* workLoop)
567 {
568  stateMachineSemaphore_.take();
569  __COUT__ << "Re-sending message..." << SOAPUtilities::translate( stateMachineWorkLoopManager_.getMessage(workLoop)).getCommand() << std::endl;
570  std::string reply = send(
571  theSupervisorDescriptorInfo_.getSupervisorDescriptor(),
572  stateMachineWorkLoopManager_.getMessage(workLoop));
573  stateMachineWorkLoopManager_.report(workLoop, reply, 100, true);
574 
575  __COUT__ << "Done with message. Reply = " << reply << std::endl;
576  stateMachineSemaphore_.give();
577 
578  if(reply == "Fault")
579  {
580  __SS__ << "Failure to send Workloop transition command! Unrecognized transition name." << std::endl;
581  __COUT_ERR__ << ss.str();
582  __MOUT_ERR__ << ss.str();
583  }
584  return false; //execute once and automatically remove the workloop so in WorkLoopManager the try workLoop->remove(job_) could be commented out
585  //return true;//go on and then you must do the workLoop->remove(job_) in WorkLoopManager
586 }
587 
588 //========================================================================================================================
589 //infoRequestHandler ~~
590 // Call from JS GUI
591 // parameter:
592 //
593 void Supervisor::infoRequestHandler(xgi::Input* in, xgi::Output* out)
594 throw (xgi::exception::Exception)
595 {
596  __COUT__ << "Starting to Request!" << std::endl;
597  cgicc::Cgicc cgi(in);
598 
599  //**** start LOGIN GATEWAY CODE ***//
600  //If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers optionally for uint8_t userPermissions, uint64_t uid
601  //Else, error message is returned in cookieCode
602  std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode");
603  uint8_t userPermissions;// uint64_t uid;
604  if (!theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, &userPermissions))
605  {
606  *out << cookieCode;
607  return;
608  }
609  //**** end LOGIN GATEWAY CODE ***//
610 
611  HttpXmlDocument xmldoc(cookieCode);
612 
613  //If the thread is canceled when you are still in this method that activated it, then everything will freeze.
614  //The way the workloop manager now works is safe since it cancel the thread only when the infoRequestResultHandler is called
615  //and that methid can be called ONLY when I am already out of here!
616 
617  HttpXmlDocument tmpDoc = infoRequestWorkLoopManager_.processRequest(cgi);
618 
619  xmldoc.copyDataChildren(tmpDoc);
620 
621  xmldoc.outputXmlDocument((std::ostringstream*) out, false);
622 }
623 
624 //========================================================================================================================
625 void Supervisor::infoRequestResultHandler(xgi::Input* in, xgi::Output* out)
626 throw (xgi::exception::Exception)
627 {
628  __COUT__ << "Starting ask!" << std::endl;
629  cgicc::Cgicc cgi(in);
630 
631  //**** start LOGIN GATEWAY CODE ***//
632  //If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers optionally for uint8_t userPermissions, uint64_t uid
633  //Else, error message is returned in cookieCode
634  std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode");
635  uint8_t userPermissions;// uint64_t uid;
636  if (!theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, &userPermissions))
637  {
638  *out << cookieCode;
639  return;
640  }
641  //**** end LOGIN GATEWAY CODE ***//
642 
643  HttpXmlDocument xmldoc(cookieCode);
644 
645  infoRequestWorkLoopManager_.getRequestResult(cgi, xmldoc);
646 
647  //return xml doc holding server response
648  xmldoc.outputXmlDocument((std::ostringstream*) out, false);
649 
650  __COUT__ << "Done asking!" << std::endl;
651 }
652 
653 //========================================================================================================================
654 bool Supervisor::infoRequestThread(toolbox::task::WorkLoop* workLoop)
655 {
656  // std::string workLoopName = workLoop->getName();
657  // __COUT__ << " Starting WorkLoop: " << workLoopName << std::endl;
658  // __COUT__ << " Ready to lock" << std::endl;
659  infoRequestSemaphore_.take();
660  // __COUT__ << " Locked" << std::endl;
661  vectorTest_.clear();
662 
663  for (unsigned long long i = 0; i < 100000000; i++)
664  {
665  counterTest_ += 2;
666  vectorTest_.push_back(counterTest_);
667  }
668 
669  infoRequestWorkLoopManager_.report(workLoop,
670  "RESULT: This is the best result ever", 50, false);
671  std::string workLoopName = workLoop->getName();
672  __COUT__ << workLoopName << " test: " << counterTest_
673  << " vector size: " << vectorTest_.size() << std::endl;
674  wait(400, "InfoRequestThread ----- locked");
675  infoRequestSemaphore_.give();
676  // __COUT__ << " Lock released" << std::endl;
677  wait(200, "InfoRequestThread");
678  // __COUT__ << " Ready to lock again" << std::endl;
679  infoRequestSemaphore_.take();
680  // __COUT__ << " Locked again" << std::endl;
681  vectorTest_.clear();
682 
683  for (unsigned long long i = 0; i < 100000000; i++)
684  {
685  counterTest_ += 2;
686  vectorTest_.push_back(counterTest_);
687  }
688 
689  wait(400, "InfoRequestThread ----- locked");
690  __COUT__ << workLoopName << " test: " << counterTest_ << " vector size: " << vectorTest_.size() << std::endl;
691  infoRequestSemaphore_.give();
692  // __COUT__ << " Lock released again" << std::endl;
693  //infoRequestWorkLoopManager_->report(workLoop,"RESULT: This is the best result ever");
694  infoRequestWorkLoopManager_.report(workLoop,
695  theStateMachine_.getCurrentStateName(), 100, true);
696  // __COUT__ << " Done with WorkLoop: " << workLoopName << std::endl;
697  return false; //execute once and automatically remove the workloop so in WorkLoopManager the try workLoop->remove(job_) could be commented out
698  //return true;//go on and then you must do the workLoop->remove(job_) in WorkLoopManager
699 }
700 
701 //========================================================================================================================
702 void Supervisor::stateInitial(toolbox::fsm::FiniteStateMachine & fsm)
703 throw (toolbox::fsm::exception::Exception)
704 {
705  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
706  //diagService_->reportError("--- Supervisor is in its Initial state ---",DIAGINFO);
707  //diagService_->reportError("Supervisor::stateInitial: workloop active: "+stringF(calibWorkloop_->isActive())+", workloop type: "+calibWorkloop_->getType(),DIAGINFO);
708 }
709 
710 //========================================================================================================================
711 void Supervisor::statePaused(toolbox::fsm::FiniteStateMachine & fsm)
712 throw (toolbox::fsm::exception::Exception)
713 {
714  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
715  /*
716  try
717 {
718  rcmsStateNotifier_.stateChanged("Paused", "");
719  }
720  catch(xcept::Exception &e)
721 {
722  diagService_->reportError("Failed to notify state change : "+ xcept::stdformat_exception_history(e),DIAGERROR);
723  }
724 
725  diagService_->reportError("Supervisor::statePaused: workloop active: "+stringF(calibWorkloop_->isActive())+", workloop type: "+calibWorkloop_->getType(),DIAGINFO);
726  */
727 }
728 
729 //========================================================================================================================
730 void Supervisor::stateRunning(toolbox::fsm::FiniteStateMachine & fsm)
731 throw (toolbox::fsm::exception::Exception)
732 {
733 
734  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
735  /*
736  try
737 {
738  rcmsStateNotifier_.stateChanged("Running", "");
739  }
740  catch(xcept::Exception &e)
741 {
742  diagService_->reportError("Failed to notify state change : "+ xcept::stdformat_exception_history(e),DIAGERROR);
743  }
744 
745  diagService_->reportError("Supervisor::stateRunning: workloop active: "+stringF(calibWorkloop_->isActive())+", workloop type: "+calibWorkloop_->getType(),DIAGINFO);
746  */
747 }
748 
749 //========================================================================================================================
750 void Supervisor::stateHalted(toolbox::fsm::FiniteStateMachine& fsm)
751 throw (toolbox::fsm::exception::Exception)
752 {
753  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
754  __COUT__ << "Fsm is in transition? " << (theStateMachine_.isInTransition()?"yes":"no") << std::endl;
755 
756 
757  /*
758  percentageConfigured_=0.0;
759  aliasesAndKeys_=PixelConfigInterface::getAliases();
760  diagService_->reportError("Supervisor::stateHalted: aliases and keys reloaded",DIAGINFO);
761  previousState_ = theStateMachine_.getCurrentStateName();
762  diagService_->reportError("Supervisor::stateHalted: workloop active: "+stringF(calibWorkloop_->isActive())+", workloop type: "+calibWorkloop_->getType(),DIAGINFO);
763 
764  //(hopefully) make RCMS aware of successful Recovery
765  //need to test that: (a) this works and (b) this does not break anything (regular Halt transition)
766  //update -- condition (b) seems to be satisfied. not yet sure about condition (a)
767  try
768 {
769  rcmsStateNotifier_.stateChanged("Halted", "");
770  }
771  catch(xcept::Exception &e)
772 
773 {
774  diagService_->reportError("Failed to notify state change : "+ xcept::stdformat_exception_history(e),DIAGERROR);
775  }
776  */
777 }
778 
779 //========================================================================================================================
780 void Supervisor::stateConfigured(toolbox::fsm::FiniteStateMachine & fsm)
781 throw (toolbox::fsm::exception::Exception)
782 {
783  /*
784  // Notify RCMS of having entered the Configured state
785  try
786 
787 {
788  //rcmsStateNotifier_.stateChanged(previousState_.toString(), "");
789  rcmsStateNotifier_.stateChanged("Configured", std::stringF(theGlobalKey_->key()) );
790  }
791  catch(xcept::Exception &e)
792 
793 {
794  diagService_->reportError("Failed to notify state change : "+ xcept::stdformat_exception_history(e),DIAGERROR);
795  }
796 
797  PixelTimer debugTimer;
798  if (extratimers_)
799 {
800  debugTimer.setName("Supervisor::stateConfigured");
801  debugTimer.printTime("RCMS notified of Configured state");
802  }
803  if (configurationTimer_.started() )
804 {
805  configurationTimer_.stop();
806 
807  std::string confsource(getenv("PIXELCONFIGURATIONBASE"));
808  if (confsource != "DB") confsource = "files";
809 
810  diagService_->reportError("Total configuration time ["+confsource+"] = "+stringF(configurationTimer_.tottime()),DIAGUSERINFO);
811  configurationTimer_.reset();
812  }
813 
814  diagService_->reportError( "Supervisor::stateConfigured: workloop active: "+stringF(calibWorkloop_->isActive())+", workloop type: "+calibWorkloop_->getType(),DIAGDEBUG);
815  */
816 }
817 
818 //void Supervisor::stateTTSTestMode (toolbox::fsm::FiniteStateMachine & fsm) throw (toolbox::fsm::exception::Exception)
819 //{
820 // previousState_ = theStateMachine_.getCurrentStateName();
821 //}
822 
823 //void Supervisor::inError (toolbox::fsm::FiniteStateMachine & fsm) throw (toolbox::fsm::exception::Exception)
824 //{
825 // previousState_ = theStateMachine_.getCurrentStateName();
826 //rcmsStateNotifier_.stateChanged("Error", "");
827 //}
828 
829 /*
830  xoap::MessageReference Supervisor::reset (xoap::MessageReference message) throw (xoap::exception::Exception)
831 
832 {
833  //diagService_->reportError("New state before reset is: " + theStateMachine_.getCurrentStateName(),DIAGINFO);
834 
835  theStateMachine_.reset();
836 
837  xoap::MessageReference reply = xoap::createMessage();
838  xoap::SOAPEnvelope envelope = reply->getSOAPPart().getEnvelope();
839  xoap::SOAPName responseName = envelope.createName("ResetResponse", "xdaq", XDAQ_NS_URI);
840  (void) envelope.getBody().addBodyElement ( responseName );
841 
842  diagService_->reportError("New state after reset is: " + theStateMachine_.getCurrentStateName(),DIAGINFO);
843 
844  return reply;
845  }
846  */
847 
848 //========================================================================================================================
849 void Supervisor::inError(toolbox::fsm::FiniteStateMachine & fsm)
850 throw (toolbox::fsm::exception::Exception)
851 {
852  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
853  //rcmsStateNotifier_.stateChanged("Error", "");
854 }
855 
856 //========================================================================================================================
857 void Supervisor::enteringError(toolbox::Event::Reference e)
858 throw (toolbox::fsm::exception::Exception)
859 {
860  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
861 
862  //extract error message and save for user interface access
863  toolbox::fsm::FailedEvent& failedEvent = dynamic_cast<toolbox::fsm::FailedEvent&> (*e);
864  __SS__ << "\nFailure performing transition from " << failedEvent.getFromState() << "-" <<
865  theStateMachine_.getStateName(failedEvent.getFromState()) <<
866  " to " << failedEvent.getToState() << "-" <<
867  theStateMachine_.getStateName(failedEvent.getToState()) <<
868  ".\n\nException:\n" << failedEvent.getException().what() << std::endl;
869  __COUT_ERR__ << "\n" << ss.str();
870 
871  theStateMachine_.setErrorMessage(ss.str());
872 
873  //FIXME .. move everything else to Error!
874  //broadcastMessage(SOAPUtilities::makeSOAPMessageReference("Error"));
875 
876  //diagService_->reportError(errstr.str(),DIAGERROR);
877 
878 }
879 
883 
884 void Supervisor::getSupervisorsStatus(void)
885 throw (toolbox::fsm::exception::Exception)
886 {
887  theSupervisorsInfo_.getSupervisorInfo().setStatus(
888  theStateMachine_.getCurrentStateName());
889  //FIXME This need to be incorporated in the broadcast method
890  try
891  {
892  for (auto& it : theSupervisorDescriptorInfo_.getFEDescriptors())
893  {
894  try
895  {
896  std::string state = send(it.second,
897  "StateMachineStateRequest");
898 
899  theSupervisorsInfo_.getFESupervisorInfo(it.first).setStatus(
900  state);
901  //diagService_->reportError("PixelFESupervisor instance "+stringF((*i_set_PixelFESupervisor)->getInstance())+" is in FSM state "+fsmState, DIAGDEBUG);
902  __COUT__ << "FESupervisor instance " << it.first << " is in FSM state " <<
903  state << std::endl;
904  __COUT__ << "Look! Here's a FEW! @@@" << std::endl;
905  }
906  catch (xdaq::exception::Exception& e)
907  {
908  __COUT_WARN__ << "Could not retrieve status from FESupervisor instance " <<
909  it.first << "." << std::endl;
910  }
911  }
912  // it = theSupervisorDescriptorInfo_.getARTDAQFEDescriptors().begin();
913  // for (; it != theSupervisorDescriptorInfo_.getARTDAQFEDescriptors().end();
914  // it++)
915  // {
916  // try
917  // {
918  // std::string state = send(it->second,
919  // "StateMachineStateRequest");
920  // theSupervisorsInfo_.getARTDAQFESupervisorInfo(it->first).setStatus(
921  // state);
922  // __COUT__ << "PixelFERSupervisor instance " << it->first << " is in FSM state " << state << std::endl;
923  // __COUT__ << "Look! Here's a FER! @@@" << std::endl;
924  // }
925  // catch (xdaq::exception::Exception& e)
926  // {
927  // //diagService_->reportError("PixelFESupervisor instance "+stringF((*i_set_PixelFESupervisor)->getInstance())+" could not report its FSM state", DIAGERROR);
928  // }
929  // }
930  for (auto& it : theSupervisorDescriptorInfo_.getARTDAQFEDataManagerDescriptors())
931  {
932  try
933  {
934  std::string state = send(it.second,
935  "StateMachineStateRequest");
936  theSupervisorsInfo_.getARTDAQFEDataManagerSupervisorInfo(it.first).setStatus(
937  state);
938  __COUT__ << "getARTDAQFEDataManagerDescriptors instance " << it.first << " is in FSM state " << state << std::endl;
939  __COUT__ << "Look! Here's a FER! @@@" << std::endl;
940  }
941  catch (xdaq::exception::Exception& e)
942  {
943  __COUT_WARN__ << "Could not retrieve status from getARTDAQFEDataManagerDescriptors instance " <<
944  it.first << "." << std::endl;
945  }
946  }
947  for (auto& it : theSupervisorDescriptorInfo_.getARTDAQDataManagerDescriptors())
948  {
949  try
950  {
951  std::string state = send(it.second,
952  "StateMachineStateRequest");
953  theSupervisorsInfo_.getARTDAQDataManagerSupervisorInfo(it.first).setStatus(
954  state);
955  __COUT__ << "getARTDAQDataManagerSupervisorInfo instance " << it.first << " is in FSM state " << state << std::endl;
956  __COUT__ << "Look! Here's a FER! @@@" << std::endl;
957  }
958  catch (xdaq::exception::Exception& e)
959  {
960  __COUT_WARN__ << "Could not retrieve status from getARTDAQDataManagerSupervisorInfo instance " <<
961  it.first << "." << std::endl;
962  }
963  }
964  }
965  catch (xdaq::exception::Exception& e)
966  {
967  __COUT_WARN__ << "No FESupervisor found in the \"daq\" group in the Configuration XML file."
968  << std::endl;
969  }
970 
971 }
972 
973 //========================================================================================================================
974 void Supervisor::transitionConfiguring(toolbox::Event::Reference e)
975 throw (toolbox::fsm::exception::Exception)
976 {
977  //theProgressBar_.resetProgressBar(0);
978 
979  theProgressBar_.step();
980 
981  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
982 
983  std::string systemAlias = SOAPUtilities::translate(
984  theStateMachine_.getCurrentMessage()).getParameters().getValue("ConfigurationAlias");
985 
986  __COUT__ << "Transition parameter: " << systemAlias << std::endl;
987 
988  theProgressBar_.step();
989 
990 
991  try
992  {
993  theConfigurationManager_->init(); //completely reset to re-align with any changes
994  }
995  catch(...)
996  {
997  __SS__ << "\nTransition to Configuring interrupted! " <<
998  "The Configuration Manager could not be initialized." << std::endl;
999 
1000  __COUT_ERR__ << "\n" << ss.str();
1001  XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
1002  return;
1003  }
1004 
1005  theProgressBar_.step();
1006 
1007  //Translate the system alias to a group name/key
1008  try
1009  {
1010  theConfigurationGroup_ = theConfigurationManager_->getConfigurationGroupFromAlias(systemAlias);
1011  }
1012  catch(...)
1013  {
1014  __COUT_INFO__ << "Exception occurred" << std::endl;
1015  }
1016 
1017  theProgressBar_.step();
1018 
1019  if(theConfigurationGroup_.second.isInvalid())
1020  {
1021  __SS__ << "\nTransition to Configuring interrupted! System Alias " <<
1022  systemAlias << " could not be translated to a group name and key." << std::endl;
1023 
1024  __COUT_ERR__ << "\n" << ss.str();
1025  XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
1026  return;
1027  }
1028 
1029  theProgressBar_.step();
1030 
1031  __COUT__ << "Configuration group name: " << theConfigurationGroup_.first << " key: " <<
1032  theConfigurationGroup_.second << std::endl;
1033 
1034  //make logbook entry
1035  {
1036  std::stringstream ss;
1037  ss << "Configuring '" << systemAlias << "' which translates to " <<
1038  theConfigurationGroup_.first << " (" << theConfigurationGroup_.second << ").";
1039  makeSystemLogbookEntry(ss.str());
1040  }
1041 
1042  theProgressBar_.step();
1043 
1044  //load and activate
1045  try
1046  {
1047  theConfigurationManager_->loadConfigurationGroup(theConfigurationGroup_.first, theConfigurationGroup_.second, true);
1048 
1049  //When configured, set the translated System Alias to be persistently active
1050  ConfigurationManagerRW tmpCfgMgr("TheSupervisor");
1051  tmpCfgMgr.activateConfigurationGroup(theConfigurationGroup_.first, theConfigurationGroup_.second);
1052  }
1053  catch(...)
1054  {
1055  __SS__ << "\nTransition to Configuring interrupted! System Alias " <<
1056  systemAlias << " was translated to " << theConfigurationGroup_.first <<
1057  " (" << theConfigurationGroup_.second << ") but could not be loaded and initialized." << std::endl;
1058  ss << "\n\nTo debug this problem, try activating this group in the Configuration GUI " <<
1059  " and detailed errors will be shown." << std::endl;
1060  __COUT_ERR__ << "\n" << ss.str();
1061  XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
1062  return;
1063  }
1064 
1065  //check if configuration dump is enabled on configure transition
1066  {
1067  ConfigurationTree configLinkNode = theConfigurationManager_->getSupervisorConfigurationNode(
1068  supervisorContextUID_, supervisorApplicationUID_);
1069  if(!configLinkNode.isDisconnected())
1070  {
1071 
1072  try //errors in dump are not tolerated
1073  {
1074  bool dumpConfiguration = true;
1075  std::string dumpFilePath, dumpFileRadix, dumpFormat;
1076  try //for backwards compatibility
1077  {
1078  ConfigurationTree fsmLinkNode = configLinkNode.getNode("LinkToStateMachineConfiguration").
1079  getNode(activeStateMachineName_);
1080  dumpConfiguration = fsmLinkNode.getNode("EnableConfigurationDumpOnConfigureTransition").
1081  getValue<bool>();
1082  dumpFilePath = fsmLinkNode.getNode("ConfigurationDumpOnConfigureFilePath").getValue<std::string>();
1083  dumpFileRadix = fsmLinkNode.getNode("ConfigurationDumpOnConfigureFileRadix").getValue<std::string>();
1084  dumpFormat = fsmLinkNode.getNode("ConfigurationDumpOnConfigureFormat").getValue<std::string>();
1085 
1086  }
1087  catch(std::runtime_error &e)
1088  {
1089  __COUT_INFO__ << "FSM configuration dump Link disconnected." << std::endl;
1090  dumpConfiguration = false;
1091  }
1092 
1093  if(dumpConfiguration)
1094  {
1095  //dump configuration
1096  theConfigurationManager_->dumpActiveConfiguration(
1097  dumpFilePath +
1098  "/" +
1099  dumpFileRadix +
1100  "_" +
1101  std::to_string(time(0)) +
1102  ".dump",
1103  dumpFormat
1104  );
1105  }
1106 
1107  }
1108  catch(std::runtime_error &e) {
1109  __SS__ << "\nTransition to Configuring interrupted! There was an error identified " <<
1110  "during the configuration dump attempt:\n\n " <<
1111  e.what() << std::endl;
1112  __COUT_ERR__ << "\n" << ss.str();
1113  XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
1114  return;
1115  }
1116  catch(...) {
1117  __SS__ << "\nTransition to Configuring interrupted! There was an error identified " <<
1118  "during the configuration dump attempt.\n\n " <<
1119  std::endl;
1120  __COUT_ERR__ << "\n" << ss.str();
1121  XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
1122  return;
1123  }
1124  }
1125  }
1126 
1127  theProgressBar_.step();
1128  SOAPParameters parameters;
1129  parameters.addParameter("ConfigurationGroupName", theConfigurationGroup_.first);
1130  parameters.addParameter("ConfigurationGroupKey", theConfigurationGroup_.second.toString());
1131 
1132  //xoap::MessageReference message = SOAPUtilities::makeSOAPMessageReference(SOAPUtilities::translate(theStateMachine_.getCurrentMessage()).getCommand(), parameters);
1133  xoap::MessageReference message = theStateMachine_.getCurrentMessage();
1134  SOAPUtilities::addParameters(message,parameters);
1135  broadcastMessage(message);
1136  theProgressBar_.step();
1137  // Advertise the exiting of this method
1138  //diagService_->reportError("Supervisor::stateConfiguring: Exiting",DIAGINFO);
1139 
1140  //save last configured group name/key
1141  saveGroupNameAndKey(theConfigurationGroup_,FSM_LAST_CONFIGURED_GROUP_ALIAS_FILE);
1142 
1143  __COUT__ << "Done" << std::endl;
1144  theProgressBar_.complete();
1145 }
1146 
1147 //========================================================================================================================
1148 void Supervisor::transitionHalting(toolbox::Event::Reference e)
1149 throw (toolbox::fsm::exception::Exception)
1150 {
1151  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
1152 
1153  makeSystemLogbookEntry("Run halting.");
1154 
1155  broadcastMessage(theStateMachine_.getCurrentMessage());
1156 }
1157 
1158 //========================================================================================================================
1159 void Supervisor::transitionInitializing(toolbox::Event::Reference e)
1160 throw (toolbox::fsm::exception::Exception)
1161 {
1162  __COUT__ << theStateMachine_.getCurrentStateName() << std::endl;
1163  // Get all Supervisors mentioned in the Configuration XML file, and
1164  // Try to handshake with them by asking for their FSM state.
1165  getSupervisorsStatus();
1166 
1167  if(!broadcastMessage(theStateMachine_.getCurrentMessage()))
1168  {
1169  __COUT__ << "I can't Initialize the supervisors!" << std::endl;
1170  }
1171 
1172  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
1173  __COUT__ << "Fsm current transition: " << theStateMachine_.getCurrentTransitionName(e->type()) << std::endl;
1174  __COUT__ << "Fsm final state: " << theStateMachine_.getTransitionFinalStateName(e->type()) << std::endl;
1175 }
1176 
1177 //========================================================================================================================
1178 void Supervisor::transitionPausing(toolbox::Event::Reference e)
1179 throw (toolbox::fsm::exception::Exception)
1180 {
1181  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
1182 
1183  makeSystemLogbookEntry("Run pausing.");
1184 
1185  broadcastMessage(theStateMachine_.getCurrentMessage());
1186 }
1187 
1188 //========================================================================================================================
1189 void Supervisor::transitionResuming(toolbox::Event::Reference e)
1190 throw (toolbox::fsm::exception::Exception)
1191 {
1192  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
1193 
1194  makeSystemLogbookEntry("Run resuming.");
1195 
1196  broadcastMessage(theStateMachine_.getCurrentMessage());
1197 }
1198 
1199 //========================================================================================================================
1200 void Supervisor::transitionStarting(toolbox::Event::Reference e)
1201 throw (toolbox::fsm::exception::Exception)
1202 {
1203  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
1204 
1205  SOAPParameters parameters("RunNumber");
1206  receive(theStateMachine_.getCurrentMessage(), parameters);
1207 
1208  std::string runNumber = parameters.getValue("RunNumber");
1209  __COUT__ << runNumber << std::endl;
1210 
1211  //check if configuration dump is enabled on configure transition
1212  {
1213  ConfigurationTree configLinkNode = theConfigurationManager_->getSupervisorConfigurationNode(
1214  supervisorContextUID_, supervisorApplicationUID_);
1215  if(!configLinkNode.isDisconnected())
1216  {
1217  try //errors in dump are not tolerated
1218  {
1219  bool dumpConfiguration = true;
1220  std::string dumpFilePath, dumpFileRadix, dumpFormat;
1221  try //for backwards compatibility
1222  {
1223  ConfigurationTree fsmLinkNode = configLinkNode.getNode("LinkToStateMachineConfiguration").
1224  getNode(activeStateMachineName_);
1225  dumpConfiguration = fsmLinkNode.getNode("EnableConfigurationDumpOnRunTransition").
1226  getValue<bool>();
1227  dumpFilePath = fsmLinkNode.getNode("ConfigurationDumpOnRunFilePath").getValue<std::string>();
1228  dumpFileRadix = fsmLinkNode.getNode("ConfigurationDumpOnRunFileRadix").getValue<std::string>();
1229  dumpFormat = fsmLinkNode.getNode("ConfigurationDumpOnRunFormat").getValue<std::string>();
1230  }
1231  catch(std::runtime_error &e)
1232  {
1233  __COUT_INFO__ << "FSM configuration dump Link disconnected." << std::endl;
1234  dumpConfiguration = false;
1235  }
1236 
1237  if(dumpConfiguration)
1238  {
1239  //dump configuration
1240  theConfigurationManager_->dumpActiveConfiguration(
1241  dumpFilePath +
1242  "/" +
1243  dumpFileRadix +
1244  "_Run" +
1245  runNumber +
1246  "_" +
1247  std::to_string(time(0)) +
1248  ".dump",
1249  dumpFormat
1250  );
1251  }
1252 
1253  }
1254  catch(std::runtime_error &e) {
1255  __SS__ << "\nTransition to Running interrupted! There was an error identified " <<
1256  "during the configuration dump attempt:\n\n " <<
1257  e.what() << std::endl;
1258  __COUT_ERR__ << "\n" << ss.str();
1259  XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
1260  return;
1261  }
1262  catch(...) {
1263  __SS__ << "\nTransition to Running interrupted! There was an error identified " <<
1264  "during the configuration dump attempt.\n\n " <<
1265  std::endl;
1266  __COUT_ERR__ << "\n" << ss.str();
1267  XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
1268  return;
1269  }
1270  }
1271  }
1272 
1273 
1274  makeSystemLogbookEntry("Run " + runNumber + " starting.");
1275 
1276  broadcastMessage(theStateMachine_.getCurrentMessage());
1277 
1278  //save last started group name/key
1279  saveGroupNameAndKey(theConfigurationGroup_,FSM_LAST_STARTED_GROUP_ALIAS_FILE);
1280 }
1281 
1282 //========================================================================================================================
1283 void Supervisor::transitionStopping(toolbox::Event::Reference e)
1284 throw (toolbox::fsm::exception::Exception)
1285 {
1286  __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << std::endl;
1287 
1288  makeSystemLogbookEntry("Run stopping.");
1289 
1290  broadcastMessage(theStateMachine_.getCurrentMessage());
1291 }
1292 
1296 
1297 //========================================================================================================================
1298 bool Supervisor::broadcastMessage(xoap::MessageReference message)
1299 throw (toolbox::fsm::exception::Exception)
1300 {
1301  std::string command = SOAPUtilities::translate(message).getCommand();
1302  bool proceed = true;
1303  std::string reply;
1304 
1305  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1306  // Send a SOAP message to FESupervisor
1307  for(auto& it: theSupervisorDescriptorInfo_.getFEDescriptors())
1308  {
1309  RunControlStateMachine::theProgressBar_.step();
1310  __COUT__ << "Sending message to FESupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1311  __COUT__ << "Sending message to FESupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1312  __COUT__ << "Sending message to FESupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1313  __COUT__ << "Sending message to FESupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1314  __COUT__ << "Sending message to FESupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1315 
1316  try
1317  {
1318  reply = send(it.second, message);
1319  }
1320  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1321  {
1322  //do not kill whole system if xdaq xoap failure
1323  __SS__ << "Can NOT " << command << " FESupervisors, instance = " << it.first << ".\n\n" <<
1324  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1325  __COUT_ERR__ << ss.str();
1326  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1327  proceed = false;
1328  }
1329 
1330  if (reply != command + "Done")
1331  {
1332  //diagService_->reportError("FESupervisor supervisor "+stringF(it->first) + " could not be initialized!",DIAGFATAL);
1333 
1334  __SS__ << "Can NOT " << command << " FESupervisor, instance = " << it.first << ".\n\n" <<
1335  reply;
1336  __COUT_ERR__ << ss.str() << std::endl;
1337 
1338  __COUT__ << "Getting error message..." << std::endl;
1339  xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("StateMachineErrorMessageRequest"));
1340  SOAPParameters parameters;
1341  parameters.addParameter("ErrorMessage");
1342  SOAPMessenger::receive(errorMessage, parameters);
1343  __COUT_ERR__ << "errorMessage = " << parameters.getValue("ErrorMessage") << std::endl;
1344  ss << "\n\nError Message: " << parameters.getValue("ErrorMessage") << std::endl;
1345  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1346  proceed = false;
1347  //}
1348  }
1349  else
1350  {
1351  __COUT__ << "FESupervisor supervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1352  }
1353  }
1354 
1355  for(auto& it: theSupervisorDescriptorInfo_.getDTCDescriptors())
1356  {
1357  RunControlStateMachine::theProgressBar_.step();
1358  __COUT__ << "Sending message to DTCSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1359  __COUT__ << "Sending message to DTCSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1360  __COUT__ << "Sending message to DTCSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1361  __COUT__ << "Sending message to DTCSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1362  __COUT__ << "Sending message to DTCSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1363 
1364  try
1365  {
1366  reply = send(it.second, message);
1367  }
1368  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1369  {
1370  //do not kill whole system if xdaq xoap failure
1371  __SS__ << "Can NOT " << command << " DTCSupervisors, instance = " << it.first << ".\n\n" <<
1372  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1373  __COUT_ERR__ << ss.str();
1374  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1375  proceed = false;
1376  }
1377 
1378  if (reply != command + "Response")
1379  {
1380  //diagService_->reportError("DTCSupervisor supervisor "+stringF(it->first) + " could not be initialized!",DIAGFATAL);
1381 
1382  __SS__ << "Can NOT " << command << " DTCSupervisor, instance = " << it.first << ".\n\n" <<
1383  reply;
1384  __COUT_ERR__ << ss.str() << std::endl;
1385 
1386  //xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("Special" + command));
1387 
1388 
1389  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1390  proceed = false;
1391  //}
1392  }
1393  else
1394  {
1395  __COUT__ << "DTCSupervisor supervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1396  }
1397  }
1398 
1399  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1400  for(auto& it: theSupervisorDescriptorInfo_.getDataManagerDescriptors())
1401  {
1402  RunControlStateMachine::theProgressBar_.step();
1403  __COUT__ << "Sending message to DataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1404  __COUT__ << "Sending message to DataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1405  __COUT__ << "Sending message to DataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1406  __COUT__ << "Sending message to DataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1407  __COUT__ << "Sending message to DataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1408 
1409  try
1410  {
1411  reply = send(it.second, message);
1412  }
1413  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1414  {
1415  //do not kill whole system if xdaq xoap failure
1416  __SS__ << "Can NOT " << command << " DataManagerSupervisors, instance = " << it.first << ".\n\n" <<
1417  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1418  __COUT_ERR__ << ss.str();
1419  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1420  proceed = false;
1421  }
1422 
1423  if (reply != command + "Done")
1424  {
1425  __SS__ << "Can NOT " << command << " DataManagerSupervisor, instance = " << it.first << ".\n\n" <<
1426  reply;
1427  __COUT_ERR__ << ss.str() << std::endl;
1428  __COUT__ << "Getting error message..." << std::endl;
1429  xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("StateMachineErrorMessageRequest"));
1430  SOAPParameters parameters;
1431  parameters.addParameter("ErrorMessage");
1432  SOAPMessenger::receive(errorMessage, parameters);
1433  __COUT_ERR__ << "errorMessage = " << parameters.getValue("ErrorMessage") << std::endl;
1434  ss << "\n\nError Message: " << parameters.getValue("ErrorMessage") << std::endl;
1435  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1436  proceed = false;
1437  }
1438  else
1439  {
1440  __COUT__ << "DataManagerSupervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1441  }
1442  }
1443 
1444  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1445  for (auto& it: theSupervisorDescriptorInfo_.getFEDataManagerDescriptors())
1446  {
1447  RunControlStateMachine::theProgressBar_.step();
1448  __COUT__ << "Sending message to FEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1449  __COUT__ << "Sending message to FEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1450  __COUT__ << "Sending message to FEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1451  __COUT__ << "Sending message to FEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1452  __COUT__ << "Sending message to FEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1453 
1454  try
1455  {
1456  reply = send(it.second, message);
1457  }
1458  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1459  {
1460  //do not kill whole system if xdaq xoap failure
1461  __SS__ << "Can NOT " << command << " FEDataManagerSupervisors, instance = " << it.first << ".\n\n" <<
1462  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1463  __COUT_ERR__ << ss.str();
1464  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1465  proceed = false;
1466  }
1467 
1468  if (reply != command + "Done")
1469  {
1470  __SS__ << "Can NOT " << command << " FEDataManagerSupervisor, instance = " << it.first << ".\n\n" <<
1471  reply;
1472  __COUT_ERR__ << ss.str() << std::endl;
1473  __COUT__ << "Getting error message..." << std::endl;
1474  xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("StateMachineErrorMessageRequest"));
1475  SOAPParameters parameters;
1476  parameters.addParameter("ErrorMessage");
1477  SOAPMessenger::receive(errorMessage, parameters);
1478  __COUT_ERR__ << "errorMessage = " << parameters.getValue("ErrorMessage") << std::endl;
1479  ss << "\n\nError Message: " << parameters.getValue("ErrorMessage") << std::endl;
1480  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1481  proceed = false;
1482  }
1483  else
1484  {
1485  __COUT__ << "FEDataManagerSupervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1486  }
1487  }
1488 
1489  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1490  for(auto& it: theSupervisorDescriptorInfo_.getVisualDescriptors())
1491  {
1492  RunControlStateMachine::theProgressBar_.step();
1493  __COUT__ << "Sending message to VisualSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1494  __COUT__ << "Sending message to VisualSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1495  __COUT__ << "Sending message to VisualSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1496  __COUT__ << "Sending message to VisualSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1497  __COUT__ << "Sending message to VisualSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1498 
1499 
1500  try
1501  {
1502  reply = send(it.second, message);
1503  }
1504  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1505  {
1506  //do not kill whole system if xdaq xoap failure
1507  __SS__ << "Can NOT " << command << " VisualSupervisor, instance = " << it.first << ".\n\n" <<
1508  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1509  __COUT_ERR__ << ss.str();
1510  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1511  proceed = false;
1512  }
1513 
1514 
1515  if (reply != command + "Done")
1516  {
1517  __SS__ << "Can NOT " << command << " VisualSupervisor, instance = " << it.first << ".\n\n" <<
1518  reply;
1519  __COUT_ERR__ << ss.str() << std::endl;
1520  __COUT__ << "Getting error message..." << std::endl;
1521  xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("StateMachineErrorMessageRequest"));
1522  SOAPParameters parameters;
1523  parameters.addParameter("ErrorMessage");
1524  SOAPMessenger::receive(errorMessage, parameters);
1525  __COUT_ERR__ << "errorMessage = " << parameters.getValue("ErrorMessage") << std::endl;
1526  ss << "\n\nError Message: " << parameters.getValue("ErrorMessage") << std::endl;
1527  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1528  proceed = false;
1529  }
1530  else
1531  {
1532  __COUT__ << "VisualSupervisor supervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1533  }
1534  }
1535 
1536  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1537  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1538  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1539 
1540  bool artdaqRestarted = false;
1541  bool artdaqWasRestarted = false;
1542 
1543  RunControlStateMachine::theProgressBar_.step();
1544  if(command == "Halt" || command == "Initialize")
1545  {
1546  //FIXME -- temporary solution for keeping artdaq mpi alive through reconfiguring
1547  // Steps: (if Halt or Initialize
1548  // - Restart
1549  // - Send Initialize
1550  // this will place artdaq supervisors in Halt state, same as others
1551 
1552  { //MPI relaunch in StartOTS.sh
1553 
1554  __COUT__ << "Extracting target context hostnames... " << std::endl;
1555  std::vector<std::string> hostnames;
1556  try
1557  {
1558  theConfigurationManager_->init(); //completely reset to re-align with any changes
1559 
1560  const XDAQContextConfiguration* contextConfiguration = theConfigurationManager_->__GET_CONFIG__(XDAQContextConfiguration);
1561 
1562  auto contexts = contextConfiguration->getContexts();
1563  unsigned int i,j;
1564  for(const auto& context: contexts)
1565  {
1566  if(!context.status_) continue;
1567 
1568  //find last slash
1569  j=0; //default to whole string
1570  for(i=0;i<context.address_.size();++i)
1571  if(context.address_[i] == '/')
1572  j = i+1;
1573  hostnames.push_back(context.address_.substr(j));
1574  __COUT__ << "hostname = " << hostnames.back() << std::endl;
1575  }
1576  }
1577  catch(...)
1578  {
1579  __SS__ << "\nTransition to Configuring interrupted! " <<
1580  "The Configuration Manager could not be initialized." << std::endl;
1581 
1582  __COUT_ERR__ << "\n" << ss.str();
1583 
1584  XCEPT_RAISE (toolbox::fsm::exception::Exception, ss.str());
1585  }
1586 
1587  for(const auto& hostname: hostnames)
1588  {
1589  std::string fn = (std::string(getenv("SERVICE_DATA_PATH")) +
1590  "/StartOTS_action_" + hostname + ".cmd");
1591  FILE* fp = fopen(fn.c_str(),"w");
1592  if(fp)
1593  {
1594  fprintf(fp,"RESET_MPI");
1595  fclose(fp);
1596  }
1597  else
1598  __COUT_ERR__ << "Unable to open command file: " << fn << std::endl;
1599  }
1600 
1601  //
1602  // FILE *fp = fopen((std::string(getenv("SERVICE_DATA_PATH")) +
1603  // "/StartOTS_action.cmd").c_str(),"w");
1604  // if(fp)
1605  // {
1606  // fprintf(fp,"RESET_MPI");
1607  // fclose(fp);
1608  //
1609  // }
1610  } //end mpi reset
1611 
1612  artdaqRestarted = true;
1613  //change message command to Initialize
1614  SOAPParameters parameters;
1615  message = SOAPUtilities::makeSOAPMessageReference(
1616  "Initialize", parameters);
1617  command = SOAPUtilities::translate(message).getCommand();
1618  __COUT__ << "command now is " << command << std::endl;
1619  }
1620  RunControlStateMachine::theProgressBar_.step();
1621 
1622 
1623  int MAX_ARTDAQ_RESTARTS = 10;
1624  int ARTDAQ_RESTART_DELAY = 2;
1625  int artdaqRestartCount = 0;
1626  bool preArtdaqProceed = proceed;
1627 
1628  ARTDAQ_RETRY: //label to jump back for artdaq retry
1629  if(artdaqWasRestarted) //wait longer
1630  {
1631  ++artdaqRestartCount;
1632  proceed = preArtdaqProceed; //reset for each try
1633  if(artdaqRestartCount < MAX_ARTDAQ_RESTARTS)
1634  artdaqWasRestarted = false; //allow another restart
1635  for(int i=0;i<ARTDAQ_RESTART_DELAY;++i)
1636  {
1637  sleep(1);
1638  __COUT_INFO__ << "Waiting on artdaq reboot... " << i << " for " << artdaqRestartCount << "x" << std::endl;
1639  }
1640  }
1641 
1642  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1643  for(auto& it: theSupervisorDescriptorInfo_.getARTDAQFEDataManagerDescriptors())
1644  {
1645  RunControlStateMachine::theProgressBar_.step();
1646  __COUT__ << "Sending message to ARTDAQFEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1647  __COUT__ << "Sending message to ARTDAQFEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1648  __COUT__ << "Sending message to ARTDAQFEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1649  __COUT__ << "Sending message to ARTDAQFEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1650  __COUT__ << "Sending message to ARTDAQFEDataManagerSupervisors: " << it.second->getLocalId() << " : " << command << std::endl;
1651 
1652  try
1653  {
1654  reply = send(it.second, message);
1655  if (reply != command + "Done")
1656  {
1657  __SS__ << "Can NOT " << command << " ARTDAQFEDataManagerSupervisor, instance = " << it.first << ".\n\n" <<
1658  reply;
1659  __COUT_ERR__ << ss.str() << std::endl;
1660  __COUT__ << "Getting error message..." << std::endl;
1661  xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("StateMachineErrorMessageRequest"));
1662  SOAPParameters parameters;
1663  parameters.addParameter("ErrorMessage");
1664  SOAPMessenger::receive(errorMessage, parameters);
1665  __COUT_ERR__ << "errorMessage = " << parameters.getValue("ErrorMessage") << std::endl;
1666  ss << "\n\nError Message: " << parameters.getValue("ErrorMessage") << std::endl;
1667  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1668  proceed = false;
1669  }
1670  else
1671  {
1672  __COUT__ << "ARTDAQFEDataManagerSupervisors supervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1673  }
1674  }
1675  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1676  {
1677  if(artdaqRestarted && !artdaqWasRestarted)
1678  {
1679  artdaqWasRestarted = true;
1680  goto ARTDAQ_RETRY;
1681  }
1682  else
1683  {
1684  //do not kill whole system if xdaq xoap failure
1685  __SS__ << "Can NOT " << command << " ARTDAQFEDataManagerSupervisor, instance = " << it.first << ".\n\n" <<
1686  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1687  __COUT_ERR__ << ss.str();
1688  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1689  proceed = false;
1690  }
1691  }
1692  catch(const toolbox::fsm::exception::Exception &e) //due to state machine failure
1693  {
1694  if(artdaqRestarted && !artdaqWasRestarted)
1695  {
1696  artdaqWasRestarted = true;
1697  goto ARTDAQ_RETRY;
1698  }
1699  else
1700  throw;
1701  }
1702  }
1703 
1704  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1705  // Whe artdaq FEs exist
1706  // for(auto& it: theSupervisorDescriptorInfo_.getARTDAQFEDescriptors())
1707  // {
1708  // ...
1709  //}
1710 
1711  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1712  for(auto& it: theSupervisorDescriptorInfo_.getARTDAQDataManagerDescriptors())
1713  {
1714  RunControlStateMachine::theProgressBar_.step();
1715  __COUT__ << "Sending message to ARTDAQDataManagerSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1716  __COUT__ << "Sending message to ARTDAQDataManagerSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1717  __COUT__ << "Sending message to ARTDAQDataManagerSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1718  __COUT__ << "Sending message to ARTDAQDataManagerSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1719  __COUT__ << "Sending message to ARTDAQDataManagerSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1720  try
1721  {
1722  reply = send(it.second, message);
1723  if (reply != command + "Done")
1724  {
1725  __SS__ << "Can NOT " << command << " ARTDAQDataManagerSupervisor, instance = " << it.first << ".\n\n" <<
1726  reply;
1727  __COUT_ERR__ << ss.str() << std::endl;
1728  __COUT__ << "Getting error message..." << std::endl;
1729  xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("StateMachineErrorMessageRequest"));
1730  SOAPParameters parameters;
1731  parameters.addParameter("ErrorMessage");
1732  SOAPMessenger::receive(errorMessage, parameters);
1733  __COUT_ERR__ << "errorMessage = " << parameters.getValue("ErrorMessage") << std::endl;
1734  ss << "\n\nError Message: " << parameters.getValue("ErrorMessage") << std::endl;
1735  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1736  proceed = false;
1737  }
1738  else
1739  {
1740  __COUT__ << "ARTDAQDataManagerSupervisor supervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1741  }
1742  }
1743  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1744  {
1745  if(artdaqRestarted && !artdaqWasRestarted)
1746  {
1747  artdaqWasRestarted = true;
1748  goto ARTDAQ_RETRY;
1749  }
1750  else
1751  {
1752  //do not kill whole system if xdaq xoap failure
1753  __SS__ << "Can NOT " << command << " ARTDAQDataManagerSupervisor, instance = " << it.first << ".\n\n" <<
1754  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1755  __COUT_ERR__ << ss.str();
1756  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1757  proceed = false;
1758  }
1759  }
1760  catch(const toolbox::fsm::exception::Exception &e) //due to state machine failure
1761  {
1762  if(artdaqRestarted && !artdaqWasRestarted)
1763  {
1764  artdaqWasRestarted = true;
1765  goto ARTDAQ_RETRY;
1766  }
1767  else
1768  throw;
1769  }
1770  }
1771 
1772  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1773  for(auto& it: theSupervisorDescriptorInfo_.getARTDAQBuilderDescriptors())
1774  {
1775  RunControlStateMachine::theProgressBar_.step();
1776  __COUT__ << "Sending message to ARTDAQBuilderSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1777  __COUT__ << "Sending message to ARTDAQBuilderSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1778  __COUT__ << "Sending message to ARTDAQBuilderSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1779  __COUT__ << "Sending message to ARTDAQBuilderSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1780  __COUT__ << "Sending message to ARTDAQBuilderSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1781 
1782  try
1783  {
1784  reply = send(it.second, message);
1785  if (reply != command + "Done")
1786  {
1787  __SS__ << "Can NOT " << command << " ARTDAQBuilderSupervisor, instance = " << it.first << ".\n\n" <<
1788  reply;
1789  __COUT_ERR__ << ss.str() << std::endl;
1790  __COUT__ << "Getting error message..." << std::endl;
1791  xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("StateMachineErrorMessageRequest"));
1792  SOAPParameters parameters;
1793  parameters.addParameter("ErrorMessage");
1794  SOAPMessenger::receive(errorMessage, parameters);
1795  __COUT_ERR__ << "errorMessage = " << parameters.getValue("ErrorMessage") << std::endl;
1796  ss << "\n\nError Message: " << parameters.getValue("ErrorMessage") << std::endl;
1797  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1798  proceed = false;
1799  }
1800  else
1801  {
1802  __COUT__ << "ARTDAQBuilderSupervisor supervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1803  }
1804  }
1805  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1806  {
1807  if(artdaqRestarted && !artdaqWasRestarted)
1808  {
1809  artdaqWasRestarted = true;
1810  goto ARTDAQ_RETRY;
1811  }
1812  else
1813  {
1814  //do not kill whole system if xdaq xoap failure
1815  __SS__ << "Can NOT " << command << " ARTDAQBuilderSupervisor, instance = " << it.first << ".\n\n" <<
1816  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1817  __COUT_ERR__ << ss.str();
1818  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1819  proceed = false;
1820  }
1821  }
1822  catch(const toolbox::fsm::exception::Exception &e) //due to state machine failure
1823  {
1824  if(artdaqRestarted && !artdaqWasRestarted)
1825  {
1826  artdaqWasRestarted = true;
1827  goto ARTDAQ_RETRY;
1828  }
1829  else
1830  throw;
1831  }
1832  }
1833 
1834  //:::::::::::::::::::::::::::::::::::::::::::::::::::::
1835  for(auto& it: theSupervisorDescriptorInfo_.getARTDAQAggregatorDescriptors())
1836  {
1837  RunControlStateMachine::theProgressBar_.step();
1838  __COUT__ << "Sending message to ARTDAQAggregatorSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1839  __COUT__ << "Sending message to ARTDAQAggregatorSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1840  __COUT__ << "Sending message to ARTDAQAggregatorSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1841  __COUT__ << "Sending message to ARTDAQAggregatorSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1842  __COUT__ << "Sending message to ARTDAQAggregatorSupervisor: " << it.second->getLocalId() << " : " << command << std::endl;
1843 
1844  try
1845  {
1846  reply = send(it.second, message);
1847  if (reply != command + "Done")
1848  {
1849  __SS__ << "Can NOT " << command << " ARTDAQAggregatorSupervisor, instance = " << it.first << ".\n\n" <<
1850  reply;
1851  __COUT_ERR__ << ss.str() << std::endl;
1852  __COUT__ << "Getting error message..." << std::endl;
1853  xoap::MessageReference errorMessage = sendWithSOAPReply(it.second, SOAPUtilities::makeSOAPMessageReference("StateMachineErrorMessageRequest"));
1854  SOAPParameters parameters;
1855  parameters.addParameter("ErrorMessage");
1856  SOAPMessenger::receive(errorMessage, parameters);
1857  __COUT_ERR__ << "errorMessage = " << parameters.getValue("ErrorMessage") << std::endl;
1858  ss << "\n\nError Message: " << parameters.getValue("ErrorMessage") << std::endl;
1859  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1860  proceed = false;
1861  }
1862  else
1863  {
1864  __COUT__ << "ARTDAQAggregatorSupervisor supervisor " << (it.first) << " was " << command << "'d correctly!" << std::endl;
1865  }
1866  }
1867  catch(const xdaq::exception::Exception &e) //due to xoap send failure
1868  {
1869  if(artdaqRestarted && !artdaqWasRestarted)
1870  {
1871  artdaqWasRestarted = true;
1872  goto ARTDAQ_RETRY;
1873  }
1874  else
1875  {
1876  //do not kill whole system if xdaq xoap failure
1877  __SS__ << "Can NOT " << command << " ARTDAQAggregatorSupervisor, instance = " << it.first << ".\n\n" <<
1878  "Xoap failure. Did the target Supervisor crash? Try restarting re-initializing or restarting otsdaq." << std::endl;
1879  __COUT_ERR__ << ss.str();
1880  XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str());
1881  proceed = false;
1882  }
1883  }
1884  catch(const toolbox::fsm::exception::Exception &e) //due to state machine failure
1885  {
1886  if(artdaqRestarted && !artdaqWasRestarted)
1887  {
1888  artdaqWasRestarted = true;
1889  goto ARTDAQ_RETRY;
1890  }
1891  else
1892  throw;
1893  }
1894  }
1895 
1896  return proceed;
1897 }
1898 
1899 //========================================================================================================================
1900 void Supervisor::wait(int milliseconds, std::string who) const
1901 {
1902  for (int s = 1; s <= milliseconds; s++)
1903  {
1904  usleep(1000);
1905 
1906  if (s % 100 == 0)
1907  __COUT__ << s << " msecs " << who << std::endl;
1908  }
1909 }
1910 
1911 //========================================================================================================================
1912 //LoginRequest
1913 // handles all users login/logout actions from web GUI.
1914 // NOTE: there are two ways for a user to be logged out: timeout or manual logout
1915 // System logbook messages are generated for login and logout
1916 void Supervisor::loginRequest(xgi::Input * in, xgi::Output * out)
1917 throw (xgi::exception::Exception)
1918 {
1919  cgicc::Cgicc cgi(in);
1920  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
1921  __COUT__ << "*** Login RequestType = " << Command << std::endl;
1922 
1923  //RequestType Commands:
1924  //login
1925  //sessionId
1926  //checkCookie
1927  //logout
1928 
1929  //always cleanup expired entries and get a vector std::string of logged out users
1930  std::vector<std::string> loggedOutUsernames;
1931  theWebUsers_.cleanupExpiredEntries(&loggedOutUsernames);
1932  for (unsigned int i = 0; i < loggedOutUsernames.size(); ++i) //Log logout for logged out users
1933  makeSystemLogbookEntry(loggedOutUsernames[i] + " login timed out.");
1934 
1935  if (Command == "sessionId")
1936  {
1937  // When client loads page, client submits unique user id and receives random sessionId from server
1938  // Whenever client submits user name and password it is jumbled by sessionId when sent to server and sent along with UUID. Server uses sessionId to unjumble.
1939  //
1940  // Server maintains list of active sessionId by UUID
1941  // sessionId expires after set time if no login attempt (e.g. 5 minutes)
1942  std::string uuid = CgiDataUtilities::postData(cgi, "uuid");
1943 
1944  std::string sid = theWebUsers_.createNewLoginSession(uuid);
1945 
1946  __COUT__ << "uuid = " << uuid << std::endl;
1947  __COUT__ << "SessionId = " << sid.substr(0, 10) << std::endl;
1948  *out << sid;
1949  }
1950  else if (Command == "checkCookie")
1951  {
1952  uint64_t uid;
1953  std::string uuid;
1954  std::string jumbledUser;
1955  std::string cookieCode;
1956 
1957  // If client has a cookie, client submits cookie and username, jumbled, to see if cookie and user are still active
1958  // if active, valid cookie code is returned and name to display, in XML
1959  // if not, return 0
1960  // params:
1961  // uuid - unique user id, to look up sessionId
1962  // ju - jumbled user name
1963  // CookieCode - cookie code to check
1964 
1965  uuid = CgiDataUtilities::postData(cgi, "uuid");
1966  jumbledUser = CgiDataUtilities::postData(cgi, "ju");
1967  cookieCode = CgiDataUtilities::postData(cgi, "cc");
1968 
1969  __COUT__ << "uuid = " << uuid << std::endl;
1970  __COUT__ << "Cookie Code = " << cookieCode.substr(0, 10) << std::endl;
1971  __COUT__ << "jumbledUser = " << jumbledUser.substr(0, 10) << std::endl;
1972 
1973  //If cookie code is good, then refresh and return with display name, else return 0 as CookieCode value
1974  uid = theWebUsers_.isCookieCodeActiveForLogin(uuid, cookieCode,
1975  jumbledUser); //after call jumbledUser holds displayName on success
1976 
1977  if (uid == theWebUsers_.NOT_FOUND_IN_DATABASE)
1978  {
1979  __COUT__ << "cookieCode invalid" << std::endl;
1980  jumbledUser = ""; //clear display name if failure
1981  cookieCode = "0";//clear cookie code if failure
1982  }
1983  else
1984  __COUT__ << "cookieCode is good." << std::endl;
1985 
1986  //return xml holding cookie code and display name
1987  HttpXmlDocument xmldoc(cookieCode, jumbledUser);
1988 
1989  theWebUsers_.insertSettingsForUser(uid, &xmldoc); //insert settings
1990 
1991  xmldoc.outputXmlDocument((std::ostringstream*) out);
1992 
1993  }
1994  else if (Command == "login")
1995  {
1996  // If login attempt or create account, jumbled user and pw are submitted
1997  // if successful, valid cookie code and display name returned.
1998  // if not, return 0
1999  // params:
2000  // uuid - unique user id, to look up sessionId
2001  // nac - new account code for first time logins
2002  // ju - jumbled user name
2003  // jp - jumbled password
2004 
2005  std::string uuid = CgiDataUtilities::postData(cgi, "uuid");
2006  std::string newAccountCode = CgiDataUtilities::postData(cgi, "nac");
2007  std::string jumbledUser = CgiDataUtilities::postData(cgi, "ju");
2008  std::string jumbledPw = CgiDataUtilities::postData(cgi, "jp");
2009 
2010  __COUT__ << "jumbledUser = " << jumbledUser.substr(0, 10) << std::endl;
2011  __COUT__ << "jumbledPw = " << jumbledPw.substr(0, 10) << std::endl;
2012  __COUT__ << "uuid = " << uuid << std::endl;
2013  __COUT__ << "nac =-" << newAccountCode << "-" << std::endl;
2014 
2015  uint64_t uid = theWebUsers_.attemptActiveSession(uuid, jumbledUser,
2016  jumbledPw, newAccountCode); //after call jumbledUser holds displayName on success
2017 
2018 
2019  if (uid == theWebUsers_.NOT_FOUND_IN_DATABASE)
2020  {
2021  __COUT__ << "cookieCode invalid" << std::endl;
2022  jumbledUser = ""; //clear display name if failure
2023  if (newAccountCode != "1")//indicates uuid not found
2024  newAccountCode = "0";//clear cookie code if failure
2025  }
2026 
2027  __COUT__ << "new cookieCode = " << newAccountCode.substr(0, 10) << std::endl;
2028 
2029  HttpXmlDocument xmldoc(newAccountCode, jumbledUser);
2030 
2031  theWebUsers_.insertSettingsForUser(uid, &xmldoc); //insert settings
2032 
2033  //insert active session count for user
2034 
2035  if (uid != theWebUsers_.NOT_FOUND_IN_DATABASE)
2036  {
2037  uint64_t asCnt = theWebUsers_.getActiveSessionCountForUser(uid) - 1; //subtract 1 to remove just started session from count
2038  char asStr[20];
2039  sprintf(asStr, "%lu", asCnt);
2040  xmldoc.addTextElementToData("user_active_session_count", asStr);
2041  }
2042 
2043  xmldoc.outputXmlDocument((std::ostringstream*) out);
2044 
2045  //Log login in logbook for active experiment
2046  makeSystemLogbookEntry(
2047  theWebUsers_.getUsersUsername(uid) + " logged in.");
2048  }
2049  else if (Command == "cert")
2050  {
2051  // If login attempt or create account, jumbled user and pw are submitted
2052  // if successful, valid cookie code and display name returned.
2053  // if not, return 0
2054  // params:
2055  // uuid - unique user id, to look up sessionId
2056  // nac - new account code for first time logins
2057  // ju - jumbled user name
2058  // jp - jumbled password
2059 
2060  std::string uuid = CgiDataUtilities::postData(cgi, "uuid");
2061  std::string jumbledEmail = cgicc::form_urldecode(CgiDataUtilities::getData(cgi, "httpsUser"));
2062  std::string username = "";
2063  std::string cookieCode = "";
2064 
2065  __COUT__ << "CERTIFICATE LOGIN REUEST RECEVIED!!!" << std::endl;
2066  __COUT__ << "jumbledEmail = " << jumbledEmail << std::endl;
2067  __COUT__ << "uuid = " << uuid << std::endl;
2068 
2069  uint64_t uid = theWebUsers_.attemptActiveSessionWithCert(uuid, jumbledEmail,
2070  cookieCode, username); //after call jumbledUser holds displayName on success
2071 
2072 
2073  if (uid == theWebUsers_.NOT_FOUND_IN_DATABASE)
2074  {
2075  __COUT__ << "cookieCode invalid" << std::endl;
2076  jumbledEmail = ""; //clear display name if failure
2077  if (cookieCode != "1")//indicates uuid not found
2078  cookieCode = "0";//clear cookie code if failure
2079  }
2080 
2081  __COUT__ << "new cookieCode = " << cookieCode.substr(0, 10) << std::endl;
2082 
2083  HttpXmlDocument xmldoc(cookieCode, jumbledEmail);
2084 
2085  theWebUsers_.insertSettingsForUser(uid, &xmldoc); //insert settings
2086 
2087  //insert active session count for user
2088 
2089  if (uid != theWebUsers_.NOT_FOUND_IN_DATABASE)
2090  {
2091  uint64_t asCnt = theWebUsers_.getActiveSessionCountForUser(uid) - 1; //subtract 1 to remove just started session from count
2092  char asStr[20];
2093  sprintf(asStr, "%lu", asCnt);
2094  xmldoc.addTextElementToData("user_active_session_count", asStr);
2095  }
2096 
2097  xmldoc.outputXmlDocument((std::ostringstream*) out);
2098 
2099  //Log login in logbook for active experiment
2100  makeSystemLogbookEntry(
2101  theWebUsers_.getUsersUsername(uid) + " logged in.");
2102  }
2103  else if (Command == "logout")
2104  {
2105  std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode");
2106  std::string logoutOthers = CgiDataUtilities::postData(cgi,
2107  "LogoutOthers");
2108 
2109  __COUT__ << "Cookie Code = " << cookieCode.substr(0, 10) << std::endl;
2110  __COUT__ << "logoutOthers = " << logoutOthers << std::endl;
2111 
2112  uint64_t uid; //get uid for possible system logbook message
2113  if (theWebUsers_.cookieCodeLogout(cookieCode, logoutOthers == "1", &uid)
2114  != theWebUsers_.NOT_FOUND_IN_DATABASE) //user logout
2115  {
2116  //if did some logging out, check if completely logged out
2117  //if so, system logbook message should be made.
2118  if (!theWebUsers_.isUserIdActive(uid))
2119  makeSystemLogbookEntry(
2120  theWebUsers_.getUsersUsername(uid) + " logged out.");
2121  }
2122  }
2123  else
2124  {
2125  __COUT__ << __LINE__ << "\tInvalid Command" << std::endl;
2126  *out << "0";
2127  }
2128 }
2129 
2130 //========================================================================================================================
2131 void Supervisor::tooltipRequest(xgi::Input * in, xgi::Output * out)
2132 throw (xgi::exception::Exception)
2133 {
2134  cgicc::Cgicc cgi(in);
2135 
2136  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
2137  __COUT__ << "Tooltip RequestType = " << Command << std::endl;
2138 
2139  //**** start LOGIN GATEWAY CODE ***//
2140  //If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers optionally for uint8_t userPermissions, uint64_t uid
2141  //Else, error message is returned in cookieCode
2142  //Notes: cookie code not refreshed if RequestType = getSystemMessages
2143  std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode");
2144  uint8_t userPermissions;
2145  uint64_t uid;
2146 
2147  if (!theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, &userPermissions,
2148  &uid, "0", false))
2149  {
2150  *out << cookieCode;
2151  return;
2152  }
2153 
2154  //**** end LOGIN GATEWAY CODE ***//
2155 
2156  HttpXmlDocument xmldoc(cookieCode);
2157 
2158  if(Command == "check")
2159  {
2160  WebUsers::tooltipCheckForUsername(
2161  theWebUsers_.getUsersUsername(uid),
2162  &xmldoc,
2163  CgiDataUtilities::getData(cgi, "srcFile"),
2164  CgiDataUtilities::getData(cgi, "srcFunc"),
2165  CgiDataUtilities::getData(cgi, "srcId"));
2166  }
2167  else if(Command == "setNeverShow")
2168  {
2169  WebUsers::tooltipSetNeverShowForUsername(
2170  theWebUsers_.getUsersUsername(uid),
2171  &xmldoc,
2172  CgiDataUtilities::getData(cgi, "srcFile"),
2173  CgiDataUtilities::getData(cgi, "srcFunc"),
2174  CgiDataUtilities::getData(cgi, "srcId"),
2175  CgiDataUtilities::getData(cgi, "doNeverShow") == "1"?true:false,
2176  CgiDataUtilities::getData(cgi, "temporarySilence") == "1"?true:false);
2177 
2178  }
2179  else
2180  __COUT__ << "Command Request, " << Command << ", not recognized." << std::endl;
2181 
2182  xmldoc.outputXmlDocument((std::ostringstream*) out, false, true);
2183 }
2184 
2185 //========================================================================================================================
2186 void Supervisor::request(xgi::Input * in, xgi::Output * out)
2187 throw (xgi::exception::Exception)
2188 {
2189  //for simplicity assume all commands should be mutually exclusive with iterator thread state machine accesses (really should just be careful with RunControlStateMachine access)
2190  if(VERBOSE_MUTEX) __COUT__ << "Waiting for FSM access" << std::endl;
2191  std::lock_guard<std::mutex> lock(stateMachineAccessMutex_);
2192  if(VERBOSE_MUTEX) __COUT__ << "Have FSM access" << std::endl;
2193 
2194  cgicc::Cgicc cgi(in);
2195 
2196  std::string Command = CgiDataUtilities::getData(cgi, "RequestType");
2197 
2198 
2199  //**** start LOGIN GATEWAY CODE ***//
2200  //If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers optionally for uint8_t userPermissions, uint64_t uid
2201  //Else, error message is returned in cookieCode
2202  //Notes: cookie code not refreshed if RequestType = getSystemMessages
2203  std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode");
2204  uint8_t userPermissions;
2205  uint64_t uid;
2206  std::string userWithLock;
2207  bool refreshCookie = Command != "getSystemMessages" &&
2208  Command != "getCurrentState" &&
2209  Command != "gatewayLaunchOTS" &&
2210  Command != "gatewayLaunchWiz";
2211 
2212  if (!theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, &userPermissions,
2213  &uid, "0",
2214  refreshCookie,
2215  &userWithLock))
2216  {
2217  *out << cookieCode;
2218  return;
2219  }
2220 
2221  //**** end LOGIN GATEWAY CODE ***//
2222 
2223  //RequestType Commands:
2224  //getSettings
2225  //setSettings
2226  //accountSettings
2227  //getAliasList
2228  //getFecList
2229  //getSystemMessages
2230  //setUserWithLock
2231  //getStateMachine
2232  //stateMatchinePreferences
2233  //getStateMachineNames
2234  //getCurrentState
2235  //getIterationPlanStatus
2236  //getErrorInStateMatchine
2237  //getDesktopIcons
2238 
2239  //resetUserTooltips
2240 
2241  //gatewayLaunchOTS
2242  //gatewayLaunchWiz
2243 
2244 
2245  HttpXmlDocument xmldoc(cookieCode);
2246 
2247  if (Command == "getSettings")
2248  {
2249  std::string accounts = CgiDataUtilities::getData(cgi, "accounts");
2250 
2251  __COUT__ << "Get Settings Request" << std::endl;
2252  __COUT__ << "accounts = " << accounts << std::endl;
2253  theWebUsers_.insertSettingsForUser(uid, &xmldoc, accounts == "1");
2254  }
2255  else if (Command == "setSettings")
2256  {
2257  std::string bgcolor = CgiDataUtilities::postData(cgi, "bgcolor");
2258  std::string dbcolor = CgiDataUtilities::postData(cgi, "dbcolor");
2259  std::string wincolor = CgiDataUtilities::postData(cgi, "wincolor");
2260  std::string layout = CgiDataUtilities::postData(cgi, "layout");
2261  std::string syslayout = CgiDataUtilities::postData(cgi, "syslayout");
2262 
2263  __COUT__ << "Set Settings Request" << std::endl;
2264  __COUT__ << "bgcolor = " << bgcolor << std::endl;
2265  __COUT__ << "dbcolor = " << dbcolor << std::endl;
2266  __COUT__ << "wincolor = " << wincolor << std::endl;
2267  __COUT__ << "layout = " << layout << std::endl;
2268  __COUT__ << "syslayout = " << syslayout << std::endl;
2269  theWebUsers_.changeSettingsForUser(uid, bgcolor, dbcolor, wincolor,
2270  layout, syslayout);
2271  theWebUsers_.insertSettingsForUser(uid, &xmldoc, true); //include user accounts
2272  }
2273  else if (Command == "accountSettings")
2274  {
2275  std::string type = CgiDataUtilities::postData(cgi, "type"); //updateAccount, createAccount, deleteAccount
2276  int type_int = -1;
2277 
2278  if (type == "updateAccount")
2279  type_int = 0;
2280  else if (type == "createAccount")
2281  type_int = 1;
2282  else if (type == "deleteAccount")
2283  type_int = 2;
2284 
2285  std::string username = CgiDataUtilities::postData(cgi, "username");
2286  std::string displayname = CgiDataUtilities::postData(cgi,
2287  "displayname");
2288  std::string email = CgiDataUtilities::postData(cgi, "useremail");
2289  std::string permissions = CgiDataUtilities::postData(cgi,
2290  "permissions");
2291  std::string accounts = CgiDataUtilities::getData(cgi, "accounts");
2292 
2293  __COUT__ << "accountSettings Request" << std::endl;
2294  __COUT__ << "type = " << type << " - " << type_int << std::endl;
2295  __COUT__ << "username = " << username << std::endl;
2296  __COUT__ << "useremail = " << email << std::endl;
2297  __COUT__ << "displayname = " << displayname << std::endl;
2298  __COUT__ << "permissions = " << permissions << std::endl;
2299 
2300  theWebUsers_.modifyAccountSettings(uid, type_int, username, displayname,email,
2301  permissions);
2302 
2303  __COUT__ << "accounts = " << accounts << std::endl;
2304 
2305  theWebUsers_.insertSettingsForUser(uid, &xmldoc, accounts == "1");
2306  }
2307  else if(Command == "stateMatchinePreferences")
2308  {
2309  std::string set = CgiDataUtilities::getData(cgi, "set");
2310  const std::string DEFAULT_FSM_VIEW = "Default_FSM_View";
2311  if(set == "1")
2312  theWebUsers_.setGenericPreference(uid, DEFAULT_FSM_VIEW,
2313  CgiDataUtilities::getData(cgi, DEFAULT_FSM_VIEW));
2314  else
2315  theWebUsers_.getGenericPreference(uid, DEFAULT_FSM_VIEW, &xmldoc);
2316  }
2317  else if(Command == "getAliasList")
2318  {
2319  std::string username = theWebUsers_.getUsersUsername(uid);
2320  std::string fsmName = CgiDataUtilities::getData(cgi, "fsmName");
2321  __COUT__ << "fsmName = " << fsmName << std::endl;
2322 
2323  std::string stateMachineAliasFilter = "*"; //default to all
2324 
2325  std::map<std::string /*alias*/,
2326  std::pair<std::string /*group name*/, ConfigurationGroupKey> > aliasMap =
2327  theConfigurationManager_->getGroupAliasesConfiguration();
2328 
2329 
2330  // get stateMachineAliasFilter if possible
2331  ConfigurationTree configLinkNode = theConfigurationManager_->getSupervisorConfigurationNode(
2332  supervisorContextUID_, supervisorApplicationUID_);
2333 
2334  if(!configLinkNode.isDisconnected())
2335  {
2336  try //for backwards compatibility
2337  {
2338  ConfigurationTree fsmLinkNode = configLinkNode.getNode("LinkToStateMachineConfiguration");
2339  if(!fsmLinkNode.isDisconnected())
2340  stateMachineAliasFilter =
2341  fsmLinkNode.getNode(fsmName + "/SystemAliasFilter").getValue<std::string>();
2342  else
2343  __COUT_INFO__ << "FSM Link disconnected." << std::endl;
2344  }
2345  catch(std::runtime_error &e) { __COUT_INFO__ << e.what() << std::endl; }
2346  catch(...) { __COUT_ERR__ << "Unknown error. Should never happen." << std::endl; }
2347  }
2348  else
2349  __COUT_INFO__ << "FSM Link disconnected." << std::endl;
2350 
2351  __COUT__ << "stateMachineAliasFilter = " << stateMachineAliasFilter << std::endl;
2352 
2353 
2354  //filter list of aliases based on stateMachineAliasFilter
2355  // ! as first character means choose those that do NOT match filter
2356  // * can be used as wild card.
2357  {
2358  bool invertFilter = stateMachineAliasFilter.size() && stateMachineAliasFilter[0] == '!';
2359  std::vector<std::string> filterArr;
2360 
2361  size_t i = 0;
2362  if(invertFilter) ++i;
2363  size_t f;
2364  std::string tmp;
2365  while((f = stateMachineAliasFilter.find('*',i)) != std::string::npos)
2366  {
2367  tmp = stateMachineAliasFilter.substr(i,f-i);
2368  i = f+1;
2369  filterArr.push_back(tmp);
2370  //__COUT__ << filterArr[filterArr.size()-1] << " " << i <<
2371  // " of " << stateMachineAliasFilter.size() << std::endl;
2372 
2373  }
2374  if(i <= stateMachineAliasFilter.size())
2375  {
2376  tmp = stateMachineAliasFilter.substr(i);
2377  filterArr.push_back(tmp);
2378  //__COUT__ << filterArr[filterArr.size()-1] << " last." << std::endl;
2379  }
2380 
2381 
2382  bool filterMatch;
2383 
2384 
2385  for(auto& aliasMapPair : aliasMap)
2386  {
2387  //__COUT__ << "aliasMapPair.first: " << aliasMapPair.first << std::endl;
2388 
2389  filterMatch = true;
2390 
2391  if(filterArr.size() == 1)
2392  {
2393  if(filterArr[0] != "" &&
2394  filterArr[0] != "*" &&
2395  aliasMapPair.first != filterArr[0])
2396  filterMatch = false;
2397  }
2398  else
2399  {
2400  i = -1;
2401  for(f=0;f<filterArr.size();++f)
2402  {
2403  if(!filterArr[f].size()) continue; //skip empty filters
2404 
2405  if(f == 0) //must start with this filter
2406  {
2407  if((i = aliasMapPair.first.find(filterArr[f])) != 0)
2408  {
2409  filterMatch = false;
2410  break;
2411  }
2412  }
2413  else if(f == filterArr.size()-1) //must end with this filter
2414  {
2415  if(aliasMapPair.first.rfind(filterArr[f]) !=
2416  aliasMapPair.first.size() - filterArr[f].size())
2417  {
2418  filterMatch = false;
2419  break;
2420  }
2421  }
2422  else if((i = aliasMapPair.first.find(filterArr[f])) ==
2423  std::string::npos)
2424  {
2425  filterMatch = false;
2426  break;
2427  }
2428  }
2429  }
2430 
2431  if(invertFilter) filterMatch = !filterMatch;
2432 
2433  //__COUT__ << "filterMatch=" << filterMatch << std::endl;
2434 
2435  if(!filterMatch) continue;
2436 
2437  xmldoc.addTextElementToData("config_alias", aliasMapPair.first);
2438  xmldoc.addTextElementToData("config_key",
2439  ConfigurationGroupKey::getFullGroupString(aliasMapPair.second.first,
2440  aliasMapPair.second.second).c_str());
2441 
2442  std::string groupComment, groupAuthor, groupCreationTime;
2443  try
2444  {
2445  theConfigurationManager_->loadConfigurationGroup(
2446  aliasMapPair.second.first,aliasMapPair.second.second,
2447  false,0,0,
2448  &groupComment, &groupAuthor, &groupCreationTime, false /*false to not load member map*/);
2449 
2450  xmldoc.addTextElementToData("config_comment", groupComment);
2451  xmldoc.addTextElementToData("config_author", groupAuthor);
2452  xmldoc.addTextElementToData("config_create_time", groupCreationTime);
2453  }
2454  catch(...)
2455  {
2456  __COUT_WARN__ << "Failed to load group metadata." << std::endl;
2457  }
2458  }
2459  }
2460 
2461  //return last group alias
2462  std::string fn = FSM_LAST_GROUP_ALIAS_PATH + FSM_LAST_GROUP_ALIAS_FILE_START +
2463  username + "." + FSM_USERS_PREFERENCES_FILETYPE;
2464  __COUT__ << "Load preferences: " << fn << std::endl;
2465  FILE *fp = fopen(fn.c_str(),"r");
2466  if(fp)
2467  {
2468  char tmpLastAlias[500];
2469  fscanf(fp,"%*s %s",tmpLastAlias);
2470  __COUT__ << "tmpLastAlias: " << tmpLastAlias << std::endl;
2471 
2472  xmldoc.addTextElementToData("UserLastConfigAlias",tmpLastAlias);
2473  fclose(fp);
2474  }
2475  }
2476  else if (Command == "getFecList")
2477  {
2478  xmldoc.addTextElementToData("fec_list", "");
2479 
2480  for (unsigned int i = 0; i< theSupervisorDescriptorInfo_.getFEDescriptors().size(); ++i)
2481  {
2482  xmldoc.addTextElementToParent("fec_url",
2483  theSupervisorDescriptorInfo_.getFEURL(i), "fec_list");
2484  xmldoc.addTextElementToParent(
2485  "fec_urn",
2486  theSupervisorDescriptorInfo_.getFEDescriptor(i)->getURN(),
2487  "fec_list");
2488  }
2489  }
2490  else if (Command == "getSystemMessages")
2491  {
2492  xmldoc.addTextElementToData("systemMessages",
2493  theSysMessenger_.getSysMsg(
2494  theWebUsers_.getUsersDisplayName(uid)));
2495 
2496  xmldoc.addTextElementToData("username_with_lock",
2497  theWebUsers_.getUserWithLock()); //always give system lock update
2498 
2499  //__COUT__ << "userWithLock " << theWebUsers_.getUserWithLock() << std::endl;
2500  }
2501  else if (Command == "setUserWithLock")
2502  {
2503  std::string username = CgiDataUtilities::postData(cgi, "username");
2504  std::string lock = CgiDataUtilities::postData(cgi, "lock");
2505  std::string accounts = CgiDataUtilities::getData(cgi, "accounts");
2506 
2507  __COUT__ << Command << std::endl;
2508  __COUT__ << "username " << username << std::endl;
2509  __COUT__ << "lock " << lock << std::endl;
2510  __COUT__ << "accounts " << accounts << std::endl;
2511  __COUT__ << "uid " << uid << std::endl;
2512 
2513  std::string tmpUserWithLock = theWebUsers_.getUserWithLock();
2514  if(!theWebUsers_.setUserWithLock(uid, lock == "1", username))
2515  xmldoc.addTextElementToData("server_alert",
2516  std::string("Set user lock action failed. You must have valid permissions and ") +
2517  "locking user must be currently logged in.");
2518 
2519  theWebUsers_.insertSettingsForUser(uid, &xmldoc, accounts == "1");
2520 
2521  if (tmpUserWithLock != theWebUsers_.getUserWithLock()) //if there was a change, broadcast system message
2522  theSysMessenger_.addSysMsg("*", theWebUsers_.getUserWithLock()
2523  == "" ? tmpUserWithLock + " has unlocked ots."
2524  : theWebUsers_.getUserWithLock()
2525  + " has locked ots.");
2526  }
2527  else if (Command == "getStateMachine")
2528  {
2529  // __COUT__ << "Getting state machine" << std::endl;
2530  std::vector<toolbox::fsm::State> states;
2531  states = theStateMachine_.getStates();
2532  char stateStr[2];
2533  stateStr[1] = '\0';
2534  std::string transName;
2535  std::string transParameter;
2536 
2537  //bool addRun, addCfg;
2538  for (unsigned int i = 0; i < states.size(); ++i)//get all states
2539  {
2540  stateStr[0] = states[i];
2541  DOMElement* stateParent = xmldoc.addTextElementToData("state", stateStr);
2542 
2543  xmldoc.addTextElementToParent("state_name", theStateMachine_.getStateName(states[i]), stateParent);
2544 
2545  //__COUT__ << "state: " << states[i] << " - " << theStateMachine_.getStateName(states[i]) << std::endl;
2546 
2547  //get all transition final states, transitionNames and actionNames from state
2548  std::map<std::string, toolbox::fsm::State, std::less<std::string> >
2549  trans = theStateMachine_.getTransitions(states[i]);
2550  std::set<std::string> actionNames = theStateMachine_.getInputs(states[i]);
2551 
2552  std::map<std::string, toolbox::fsm::State, std::less<std::string> >::iterator it =
2553  trans.begin();
2554  std::set<std::string>::iterator ait = actionNames.begin();
2555 
2556  // addRun = false;
2557  // addCfg = false;
2558 
2559  //handle hacky way to keep "forward" moving states on right of FSM display
2560  //must be first!
2561 
2562  for (; it != trans.end() && ait != actionNames.end(); ++it, ++ait)
2563  {
2564  stateStr[0] = it->second;
2565 
2566  if(stateStr[0] == 'R')
2567  {
2568  //addRun = true;
2569  xmldoc.addTextElementToParent("state_transition", stateStr, stateParent);
2570 
2571  //__COUT__ << states[i] << " => " << *ait << std::endl;
2572 
2573  xmldoc.addTextElementToParent("state_transition_action", *ait, stateParent);
2574 
2575  transName = theStateMachine_.getTransitionName(states[i], *ait);
2576  //__COUT__ << states[i] << " => " << transName << std::endl;
2577 
2578  xmldoc.addTextElementToParent("state_transition_name",
2579  transName, stateParent);
2580  transParameter = theStateMachine_.getTransitionParameter(states[i], *ait);
2581  //__COUT__ << states[i] << " => " << transParameter<< std::endl;
2582 
2583  xmldoc.addTextElementToParent("state_transition_parameter", transParameter, stateParent);
2584  break;
2585  }
2586  else if(stateStr[0] == 'C')
2587  {
2588  //addCfg = true;
2589  xmldoc.addTextElementToParent("state_transition", stateStr, stateParent);
2590 
2591  //__COUT__ << states[i] << " => " << *ait << std::endl;
2592 
2593  xmldoc.addTextElementToParent("state_transition_action", *ait, stateParent);
2594 
2595  transName = theStateMachine_.getTransitionName(states[i], *ait);
2596  //__COUT__ << states[i] << " => " << transName << std::endl;
2597 
2598  xmldoc.addTextElementToParent("state_transition_name",
2599  transName, stateParent);
2600  transParameter = theStateMachine_.getTransitionParameter(states[i], *ait);
2601  //__COUT__ << states[i] << " => " << transParameter<< std::endl;
2602 
2603  xmldoc.addTextElementToParent("state_transition_parameter", transParameter, stateParent);
2604  break;
2605  }
2606  }
2607 
2608  //reset for 2nd pass
2609  it = trans.begin();
2610  ait = actionNames.begin();
2611 
2612  //other states
2613  for (; it != trans.end() && ait != actionNames.end(); ++it, ++ait)
2614  {
2615  //__COUT__ << states[i] << " => " << it->second << std::endl;
2616 
2617  stateStr[0] = it->second;
2618 
2619  if(stateStr[0] == 'R')
2620  continue;
2621  else if(stateStr[0] == 'C')
2622  continue;
2623 
2624  xmldoc.addTextElementToParent("state_transition", stateStr, stateParent);
2625 
2626  //__COUT__ << states[i] << " => " << *ait << std::endl;
2627 
2628  xmldoc.addTextElementToParent("state_transition_action", *ait, stateParent);
2629 
2630  transName = theStateMachine_.getTransitionName(states[i], *ait);
2631  //__COUT__ << states[i] << " => " << transName << std::endl;
2632 
2633  xmldoc.addTextElementToParent("state_transition_name",
2634  transName, stateParent);
2635  transParameter = theStateMachine_.getTransitionParameter(states[i], *ait);
2636  //__COUT__ << states[i] << " => " << transParameter<< std::endl;
2637 
2638  xmldoc.addTextElementToParent("state_transition_parameter", transParameter, stateParent);
2639  }
2640  }
2641 
2642  }
2643  else if (Command == "getStateMachineNames")
2644  {
2645  //get stateMachineAliasFilter if possible
2646  ConfigurationTree configLinkNode = theConfigurationManager_->getSupervisorConfigurationNode(
2647  supervisorContextUID_, supervisorApplicationUID_);
2648 
2649  try
2650  {
2651  auto fsmNodes = configLinkNode.getNode(
2652  "LinkToStateMachineConfiguration").getChildren();
2653  for(const auto& fsmNode:fsmNodes)
2654  xmldoc.addTextElementToData("stateMachineName", fsmNode.first);
2655  }
2656  catch(...) //else empty set of state machines.. can always choose ""
2657  {
2658  __COUT__ << "Caught exception, assuming no valid FSM names." << std::endl;
2659  xmldoc.addTextElementToData("stateMachineName", "");
2660  }
2661  }
2662  else if (Command == "getIterationPlanStatus")
2663  {
2664  //__COUT__ << "checking it status" << std::endl;
2665  theIterator_.handleCommandRequest(xmldoc,Command,"");
2666  }
2667  else if (Command == "getCurrentState")
2668  {
2669  xmldoc.addTextElementToData("current_state", theStateMachine_.getCurrentStateName());
2670  xmldoc.addTextElementToData("in_transition", theStateMachine_.isInTransition() ? "1" : "0");
2671  if (theStateMachine_.isInTransition())
2672  xmldoc.addTextElementToData("transition_progress", theProgressBar_.readPercentageString());
2673  else
2674  xmldoc.addTextElementToData("transition_progress", "100");
2675 
2676 
2677  char tmp[20];
2678  sprintf(tmp,"%lu",theStateMachine_.getTimeInState());
2679  xmldoc.addTextElementToData("time_in_state", tmp);
2680 
2681 
2682 
2683  //__COUT__ << "current state: " << theStateMachine_.getCurrentStateName() << std::endl;
2684 
2685 
2687 
2688  std::string fsmName = CgiDataUtilities::getData(cgi, "fsmName");
2689  // __COUT__ << "fsmName = " << fsmName << std::endl;
2690  // __COUT__ << "activeStateMachineName_ = " << activeStateMachineName_ << std::endl;
2691  // __COUT__ << "theStateMachine_.getProvenanceStateName() = " <<
2692  // theStateMachine_.getProvenanceStateName() << std::endl;
2693  // __COUT__ << "theStateMachine_.getCurrentStateName() = " <<
2694  // theStateMachine_.getCurrentStateName() << std::endl;
2695 
2696  if(!theStateMachine_.isInTransition())
2697  {
2698  std::string stateMachineRunAlias = "Run"; //default to "Run"
2699 
2700  // get stateMachineAliasFilter if possible
2701  ConfigurationTree configLinkNode = theConfigurationManager_->getSupervisorConfigurationNode(
2702  supervisorContextUID_, supervisorApplicationUID_);
2703 
2704  if(!configLinkNode.isDisconnected())
2705  {
2706  try //for backwards compatibility
2707  {
2708  ConfigurationTree fsmLinkNode = configLinkNode.getNode("LinkToStateMachineConfiguration");
2709  if(!fsmLinkNode.isDisconnected())
2710  stateMachineRunAlias =
2711  fsmLinkNode.getNode(fsmName + "/RunDisplayAlias").getValue<std::string>();
2712  //else
2713  // __COUT_INFO__ << "FSM Link disconnected." << std::endl;
2714  }
2715  catch(std::runtime_error &e)
2716  {
2717  //__COUT_INFO__ << e.what() << std::endl;
2718  //__COUT_INFO__ << "No state machine Run alias. Ignoring and assuming alias of '" <<
2719  // stateMachineRunAlias << ".'" << std::endl;
2720 
2721  }
2722  catch(...) {
2723  __COUT_ERR__ << "Unknown error. Should never happen." << std::endl;
2724 
2725  __COUT_INFO__ << "No state machine Run alias. Ignoring and assuming alias of '" <<
2726  stateMachineRunAlias << ".'" << std::endl;
2727  }
2728  }
2729  //else
2730  // __COUT_INFO__ << "FSM Link disconnected." << std::endl;
2731 
2732  //__COUT__ << "stateMachineRunAlias = " << stateMachineRunAlias << std::endl;
2733 
2734  xmldoc.addTextElementToData("stateMachineRunAlias", stateMachineRunAlias);
2735 
2736 
2738 
2739 
2740  if(theStateMachine_.getCurrentStateName() == "Running" ||
2741  theStateMachine_.getCurrentStateName() == "Paused")
2742  sprintf(tmp,"Current %s Number: %u",stateMachineRunAlias.c_str(),getNextRunNumber(activeStateMachineName_)-1);
2743  else
2744  sprintf(tmp,"Next %s Number: %u",stateMachineRunAlias.c_str(),getNextRunNumber(fsmName));
2745  xmldoc.addTextElementToData("run_number", tmp);
2746  }
2747  }
2748  else if(Command == "getErrorInStateMatchine")
2749  {
2750  xmldoc.addTextElementToData("FSM_Error", theStateMachine_.getErrorMessage());
2751  }
2752  else if(Command == "getDesktopIcons")
2753  {
2754 
2755  std::string iconFileName = ICON_FILE_NAME;
2756  std::ifstream iconFile;
2757  std::string iconList = "";
2758  std::string line;
2759  iconFile.open(iconFileName.c_str());
2760 
2761  if(!iconFile)
2762  {
2763  __COUT__ << "Error opening file: "<< iconFileName << std::endl;
2764  system("pause");
2765  return;
2766  }
2767  if(iconFile.is_open())
2768  {
2769  __COUT__ << "Getting Desktop Icons - opened file: " << iconFileName << std::endl;
2770  while(std::getline(iconFile, line))
2771  {
2772  iconList = line;
2773  }
2774  //__COUT__ << iconList << std::endl;
2775 
2776  //Close file
2777  iconFile.close();
2778  }
2779  xmldoc.addTextElementToData("iconList", iconList);
2780 
2781  }
2782  else if(Command == "gatewayLaunchOTS" || Command == "gatewayLaunchWiz")
2783  {
2784  //NOTE: similar to ConfigurationGUI version but DOES keep active sessions
2785 
2786  if(userPermissions != 255)
2787  {
2788  __COUT__ << "Insufficient Permissions" << std::endl;
2789  }
2790  else
2791  {
2792  __COUT_WARN__ << Command << " command received! " << std::endl;
2793  __MOUT_WARN__ << Command << " command received! " << std::endl;
2794 
2795 
2796  //gateway launch is different, in that it saves user sessions
2797  theWebUsers_.saveActiveSessions();
2798 
2799  //now launch
2800  __COUT_INFO__ << "Launching... " << std::endl;
2801 
2802 
2803  __COUT__ << "Extracting target context hostnames... " << std::endl;
2804  std::vector<std::string> hostnames;
2805  try
2806  {
2807  theConfigurationManager_->init(); //completely reset to re-align with any changes
2808 
2809  const XDAQContextConfiguration* contextConfiguration = theConfigurationManager_->__GET_CONFIG__(XDAQContextConfiguration);
2810 
2811  auto contexts = contextConfiguration->getContexts();
2812  unsigned int i,j;
2813  for(const auto& context: contexts)
2814  {
2815  if(!context.status_) continue;
2816 
2817  //find last slash
2818  j=0; //default to whole string
2819  for(i=0;i<context.address_.size();++i)
2820  if(context.address_[i] == '/')
2821  j = i+1;
2822  hostnames.push_back(context.address_.substr(j));
2823  __COUT__ << "hostname = " << hostnames.back() << std::endl;
2824  }
2825  }
2826  catch(...)
2827  {
2828  __SS__ << "\nRelaunch of otsdaq interrupted! " <<
2829  "The Configuration Manager could not be initialized." << std::endl;
2830 
2831  __COUT_ERR__ << "\n" << ss.str();
2832  return;
2833  }
2834 
2835  for(const auto& hostname: hostnames)
2836  {
2837  std::string fn = (std::string(getenv("SERVICE_DATA_PATH")) +
2838  "/StartOTS_action_" + hostname + ".cmd");
2839  FILE* fp = fopen(fn.c_str(),"w");
2840  if(fp)
2841  {
2842  if(Command == "gatewayLaunchOTS")
2843  fprintf(fp,"LAUNCH_OTS");
2844  else if(Command == "gatewayLaunchWiz")
2845  fprintf(fp,"LAUNCH_WIZ");
2846 
2847  fclose(fp);
2848  }
2849  else
2850  __COUT_ERR__ << "Unable to open command file: " << fn << std::endl;
2851  }
2852  }
2853  }
2854  else if(Command == "resetUserTooltips")
2855  {
2856  WebUsers::resetAllUserTooltips(theWebUsers_.getUsersUsername(uid));
2857  }
2858  else
2859  __COUT__ << "Command Request, " << Command << ", not recognized." << std::endl;
2860 
2861  //__COUT__ << "Made it" << std::endl;
2862 
2863  //return xml doc holding server response
2864  xmldoc.outputXmlDocument((std::ostringstream*) out, false, true); //Note: allow white space need for error response
2865 
2866  //__COUT__ << "done " << Command << std::endl;
2867 }
2868 
2869 //========================================================================================================================
2870 //xoap::supervisorGetUserInfo
2871 // get user info to external supervisors
2872 xoap::MessageReference Supervisor::supervisorGetUserInfo(
2873  xoap::MessageReference message)
2874 throw (xoap::exception::Exception)
2875 {
2876  SOAPParameters parameters;
2877  parameters.addParameter("CookieCode");
2878  receive(message, parameters);
2879  std::string cookieCode = parameters.getValue("CookieCode");
2880 
2881  std::string username, displayName;
2882  uint64_t activeSessionIndex;
2883 
2884  theWebUsers_.getUserInfoForCookie(cookieCode, &username, &displayName,
2885  &activeSessionIndex);
2886 
2887  //__COUT__ << "username " << username << std::endl;
2888  //__COUT__ << "displayName " << displayName << std::endl;
2889 
2890  //fill return parameters
2891  SOAPParameters retParameters;
2892  retParameters.addParameter("Username", username);
2893  retParameters.addParameter("DisplayName", displayName);
2894  char tmpStr[100];
2895  sprintf(tmpStr, "%lu", activeSessionIndex);
2896  retParameters.addParameter("ActiveSessionIndex", tmpStr);
2897 
2898  return SOAPUtilities::makeSOAPMessageReference("UserInfoResponse",
2899  retParameters);
2900 }
2901 
2902 //========================================================================================================================
2903 //xoap::supervisorCookieCheck
2904 // verify cookie
2905 xoap::MessageReference Supervisor::supervisorCookieCheck(xoap::MessageReference message)
2906 throw (xoap::exception::Exception)
2907 {
2908  //__COUT__ << std::endl;
2909 
2910  //receive request parameters
2911  SOAPParameters parameters;
2912  parameters.addParameter("CookieCode");
2913  parameters.addParameter("RefreshOption");
2914  receive(message, parameters);
2915  std::string cookieCode = parameters.getValue("CookieCode");
2916  std::string refreshOption = parameters.getValue("RefreshOption"); //give external supervisors option to refresh cookie or not, "1" to refresh
2917 
2918  //If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers optionally for uint8_t userPermissions, uint64_t uid
2919  //Else, error message is returned in cookieCode
2920  uint8_t userPermissions = 0;
2921  std::string userWithLock = "";
2922  theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, &userPermissions, 0,
2923  "0", refreshOption == "1", &userWithLock);
2924 
2925  //__COUT__ << "userWithLock " << userWithLock << std::endl;
2926 
2927  //fill return parameters
2928  SOAPParameters retParameters;
2929  retParameters.addParameter("CookieCode", cookieCode);
2930  char tmp[5];
2931  sprintf(tmp, "%d", userPermissions);
2932  retParameters.addParameter("Permissions", tmp);
2933  retParameters.addParameter("UserWithLock", userWithLock);
2934 
2935  //__COUT__ << std::endl;
2936 
2937  return SOAPUtilities::makeSOAPMessageReference("CookieResponse",
2938  retParameters);
2939 }
2940 
2941 //========================================================================================================================
2942 //xoap::supervisorGetActiveUsers
2943 // get display names for all active users
2944 xoap::MessageReference Supervisor::supervisorGetActiveUsers(
2945  xoap::MessageReference message)
2946 throw (xoap::exception::Exception)
2947 {
2948  __COUT__ << std::endl;
2949 
2951  parameters("UserList", theWebUsers_.getActiveUsersString());
2952  return SOAPUtilities::makeSOAPMessageReference("ActiveUserResponse",
2953  parameters);
2954 }
2955 
2956 //========================================================================================================================
2957 //xoap::supervisorSystemMessage
2958 // receive a new system Message from a supervisor
2959 // ToUser wild card * is to all users
2960 xoap::MessageReference Supervisor::supervisorSystemMessage(
2961  xoap::MessageReference message)
2962 throw (xoap::exception::Exception)
2963 {
2964  SOAPParameters parameters;
2965  parameters.addParameter("ToUser");
2966  parameters.addParameter("Message");
2967  receive(message, parameters);
2968 
2969  __COUT__ << "toUser: " << parameters.getValue("ToUser").substr(
2970  0, 10) << ", message: " << parameters.getValue("Message").substr(0,
2971  10) << std::endl;
2972 
2973  theSysMessenger_.addSysMsg(parameters.getValue("ToUser"),
2974  parameters.getValue("Message"));
2975  return SOAPUtilities::makeSOAPMessageReference("SystemMessageResponse");
2976 }
2977 
2978 //===================================================================================================================
2979 //xoap::supervisorSystemLogbookEntry
2980 // receive a new system Message from a supervisor
2981 // ToUser wild card * is to all users
2982 xoap::MessageReference Supervisor::supervisorSystemLogbookEntry(
2983  xoap::MessageReference message)
2984 throw (xoap::exception::Exception)
2985 {
2986  SOAPParameters parameters;
2987  parameters.addParameter("EntryText");
2988  receive(message, parameters);
2989 
2990  __COUT__ << "EntryText: " << parameters.getValue("EntryText").substr(
2991  0, 10) << std::endl;
2992 
2993  makeSystemLogbookEntry(parameters.getValue("EntryText"));
2994 
2995  return SOAPUtilities::makeSOAPMessageReference("SystemLogbookResponse");
2996 }
2997 
2998 //===================================================================================================================
2999 //supervisorLastConfigGroupRequest
3000 // return the group name and key for the last state machine activity
3001 //
3002 // Note: same as OtsConfigurationWizardSupervisor::supervisorLastConfigGroupRequest
3003 xoap::MessageReference Supervisor::supervisorLastConfigGroupRequest(
3004  xoap::MessageReference message)
3005 throw (xoap::exception::Exception)
3006 {
3007  SOAPParameters parameters;
3008  parameters.addParameter("ActionOfLastGroup");
3009  receive(message, parameters);
3010 
3011  return Supervisor::lastConfigGroupRequestHandler(parameters);
3012 }
3013 
3014 //===================================================================================================================
3015 //xoap::lastConfigGroupRequestHandler
3016 // handles last config group request.
3017 // called by both:
3018 // Supervisor::supervisorLastConfigGroupRequest
3019 // OtsConfigurationWizardSupervisor::supervisorLastConfigGroupRequest
3020 xoap::MessageReference Supervisor::lastConfigGroupRequestHandler(
3021  const SOAPParameters &parameters)
3022 {
3023  std::string action = parameters.getValue("ActionOfLastGroup");
3024  __COUT__ << "ActionOfLastGroup: " << action.substr(
3025  0, 10) << std::endl;
3026 
3027  std::string fileName = "";
3028  if(action == "Configured")
3029  fileName = FSM_LAST_CONFIGURED_GROUP_ALIAS_FILE;
3030  else if(action == "Started")
3031  fileName = FSM_LAST_STARTED_GROUP_ALIAS_FILE;
3032  else
3033  {
3034  __COUT_ERR__ << "Invalid last group action requested." << std::endl;
3035  return SOAPUtilities::makeSOAPMessageReference("LastConfigGroupResponseFailure");
3036  }
3037  std::string timeString;
3038  std::pair<std::string /*group name*/, ConfigurationGroupKey> theGroup =
3039  loadGroupNameAndKey(fileName,timeString);
3040 
3041  //fill return parameters
3042  SOAPParameters retParameters;
3043  retParameters.addParameter("GroupName", theGroup.first);
3044  retParameters.addParameter("GroupKey", theGroup.second.toString());
3045  retParameters.addParameter("GroupAction", action);
3046  retParameters.addParameter("GroupActionTime", timeString);
3047 
3048 
3049  return SOAPUtilities::makeSOAPMessageReference("LastConfigGroupResponse",
3050  retParameters);
3051 }
3052 
3053 //========================================================================================================================
3054 //getNextRunNumber
3055 //
3056 // If fsmName is passed, then get next run number for that FSM name
3057 // Else get next run number for the active FSM name, activeStateMachineName_
3058 //
3059 // Note: the FSM name is sanitized of special characters and used in the filename.
3060 unsigned int Supervisor::getNextRunNumber(const std::string &fsmNameIn)
3061 {
3062  std::string runNumberFileName = RUN_NUMBER_PATH + "/";
3063  std::string fsmName = fsmNameIn == ""?activeStateMachineName_:fsmNameIn;
3064  //prepend sanitized FSM name
3065  for(unsigned int i=0;i<fsmName.size();++i)
3066  if( (fsmName[i] >= 'a' && fsmName[i] <= 'z') ||
3067  (fsmName[i] >= 'A' && fsmName[i] <= 'Z') ||
3068  (fsmName[i] >= '0' && fsmName[i] <= '9'))
3069  runNumberFileName += fsmName[i];
3070  runNumberFileName += RUN_NUMBER_FILE_NAME;
3071  //__COUT__ << "runNumberFileName: " << runNumberFileName << std::endl;
3072 
3073  std::ifstream runNumberFile(runNumberFileName.c_str());
3074  if (!runNumberFile.is_open())
3075  {
3076  __COUT__ << "Can't open file: " << runNumberFileName << std::endl;
3077 
3078  __COUT__ << "Creating file and setting Run Number to 1: " << runNumberFileName << std::endl;
3079  FILE *fp = fopen(runNumberFileName.c_str(),"w");
3080  fprintf(fp,"1");
3081  fclose(fp);
3082 
3083  runNumberFile.open(runNumberFileName.c_str());
3084  if(!runNumberFile.is_open())
3085  {
3086  __SS__ << "Error. Can't create file: " << runNumberFileName << std::endl;
3087  __COUT_ERR__ << ss.str();
3088  throw std::runtime_error(ss.str());
3089  }
3090  }
3091  std::string runNumberString;
3092  runNumberFile >> runNumberString;
3093  runNumberFile.close();
3094  return atoi(runNumberString.c_str());
3095 }
3096 
3097 //========================================================================================================================
3098 bool Supervisor::setNextRunNumber(unsigned int runNumber, const std::string &fsmNameIn)
3099 {
3100  std::string runNumberFileName = RUN_NUMBER_PATH + "/";
3101  std::string fsmName = fsmNameIn == ""?activeStateMachineName_:fsmNameIn;
3102  //prepend sanitized FSM name
3103  for(unsigned int i=0;i<fsmName.size();++i)
3104  if( (fsmName[i] >= 'a' && fsmName[i] <= 'z') ||
3105  (fsmName[i] >= 'A' && fsmName[i] <= 'Z') ||
3106  (fsmName[i] >= '0' && fsmName[i] <= '9'))
3107  runNumberFileName += fsmName[i];
3108  runNumberFileName += RUN_NUMBER_FILE_NAME;
3109  __COUT__ << "runNumberFileName: " << runNumberFileName << std::endl;
3110 
3111  std::ofstream runNumberFile(runNumberFileName.c_str());
3112  if (!runNumberFile.is_open())
3113  {
3114  __SS__ << "Can't open file: " << runNumberFileName << std::endl;
3115  __COUT__ << ss.str();
3116  throw std::runtime_error(ss.str());
3117  }
3118  std::stringstream runNumberStream;
3119  runNumberStream << runNumber;
3120  runNumberFile << runNumberStream.str().c_str();
3121  runNumberFile.close();
3122  return true;
3123 }
3124 
3125 //========================================================================================================================
3126 //loadGroupNameAndKey
3127 // loads group name and key (and time) from specified file
3128 // returns time string in returnedTimeString
3129 //
3130 // Note: this is static so the OtsConfigurationWizardSupervisor can call it
3131 std::pair<std::string /*group name*/,
3132 ConfigurationGroupKey> Supervisor::loadGroupNameAndKey(const std::string &fileName,
3133  std::string &returnedTimeString)
3134 {
3135  std::string fullPath = FSM_LAST_GROUP_ALIAS_PATH + "/" + fileName;
3136 
3137  FILE *groupFile = fopen(fullPath.c_str(),"r");
3138  if (!groupFile)
3139  {
3140  __COUT__ << "Can't open file: " << fullPath << std::endl;
3141 
3142  __COUT__ << "Returning empty groupName and key -1" << std::endl;
3143 
3144  return std::pair<std::string /*group name*/,
3145  ConfigurationGroupKey>("",ConfigurationGroupKey());
3146  }
3147 
3148  char line[500]; //assuming no group names longer than 500 chars
3149  //name and then key
3150  std::pair<std::string /*group name*/,
3151  ConfigurationGroupKey> theGroup;
3152 
3153  fgets(line,500,groupFile); //name
3154  theGroup.first = line;
3155 
3156  fgets(line,500,groupFile); //key
3157  int key;
3158  sscanf(line,"%d",&key);
3159  theGroup.second = key;
3160 
3161  fgets(line,500,groupFile); //time
3162  time_t timestamp;
3163  sscanf(line,"%ld",&timestamp); //type long int
3164  struct tm tmstruct;
3165  ::localtime_r(&timestamp, &tmstruct);
3166  ::strftime(line, 30, "%c %Z", &tmstruct);
3167  returnedTimeString = line;
3168  fclose(groupFile);
3169 
3170 
3171  __COUT__ << "theGroup.first= " << theGroup.first <<
3172  " theGroup.second= " << theGroup.second << std::endl;
3173 
3174  return theGroup;
3175 }
3176 
3177 //========================================================================================================================
3178 void Supervisor::saveGroupNameAndKey(const std::pair<std::string /*group name*/,
3179  ConfigurationGroupKey> &theGroup,
3180  const std::string &fileName)
3181 {
3182  std::string fullPath = FSM_LAST_GROUP_ALIAS_PATH + "/" + fileName;
3183 
3184  std::ofstream groupFile(fullPath.c_str());
3185  if (!groupFile.is_open())
3186  {
3187  __SS__ << "Error. Can't open file: " << fullPath << std::endl;
3188  __COUT_ERR__ << "\n" << ss.str();
3189  throw std::runtime_error(ss.str());
3190  }
3191  std::stringstream outss;
3192  outss << theGroup.first << "\n" << theGroup.second << "\n" << time(0);
3193  groupFile << outss.str().c_str();
3194  groupFile.close();
3195 }
3196 
3197 
3198 
3200 
3201 
3204 //void Supervisor::infoRequest(xgi::Input * in, xgi::Output * out ) throw (xgi::exception::Exception)
3205 //{
3206 // __COUT__ << __LINE__ << std::endl << std::endl;
3207 // cgicc::Cgicc cgi(in);
3208 // std::string Command=cgi.getElement("RequestType")->getValue();
3209 //
3210 // if (Command=="FEWList")
3211 // {
3212 // *out << "<FEWList>" << std::endl;
3213 // for (std::set<xdaq::ApplicationDescriptor*>::iterator pxFESupervisorsIt=pxFESupervisors_.begin(); pxFESupervisorsIt!=pxFESupervisors_.end(); pxFESupervisorsIt++)
3214 // {
3215 // *out << "<FEWInterface id='1' alias='FPIX Disk 1' type='OtsUDPHardware'>" << std::endl
3216 // << "<svg xmlns='http://www.w3.org/2000/svg' version='1.1'>" << std::endl
3217 // << "<circle cx='100' cy='50' r='40' stroke='black' stroke-width='2' fill='red' />" << std::endl
3218 // << "</svg>" << std::endl
3219 // << "</FEWInterface>" << std::endl;
3220 // *out << "<FEWInterface id='2' alias='FPIX Disk 2' type='OtsUDPHardware'>" << std::endl
3221 // << "<svg xmlns='http://www.w3.org/2000/svg' version='1.1'>" << std::endl
3222 // << "<circle cx='100' cy='50' r='40' stroke='black' stroke-width='2' fill='red' />" << std::endl
3223 // << "</svg>" << std::endl
3224 // << "</FEWInterface>" << std::endl;
3225 // }
3226 // *out << "</FEWList>" << std::endl;
3227 // }
3228 //}
3229 //========================================================================================================================
3230