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