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