otsdaq  v2_01_00
CoreSupervisorBase.cc
1 #include "otsdaq-core/CoreSupervisors/CoreSupervisorBase.h"
2 
3 //#include "otsdaq-core/Singleton/Singleton.h"
4 //#include "otsdaq-core/FECore/FEVInterfacesManager.h"
5 
6 
7 
8 #include <iostream>
9 
10 using namespace ots;
11 
12 //XDAQ_INSTANTIATOR_IMPL(CoreSupervisorBase)
13 
14 
15 const std::string CoreSupervisorBase::WORK_LOOP_DONE = "Done";
16 const std::string CoreSupervisorBase::WORK_LOOP_WORKING = "Working";
17 
18 //========================================================================================================================
19 CoreSupervisorBase::CoreSupervisorBase(xdaq::ApplicationStub * s)
20 : xdaq::Application (s)
21 , SOAPMessenger (this)
23 , RunControlStateMachine (CorePropertySupervisorBase::allSupervisorInfo_.isWizardMode()? //set state machine name
24  CorePropertySupervisorBase::supervisorClassNoNamespace_:
25  CorePropertySupervisorBase::supervisorClassNoNamespace_ + ":" + CorePropertySupervisorBase::supervisorApplicationUID_)
26 , stateMachineWorkLoopManager_ (toolbox::task::bind(this, &CoreSupervisorBase::stateMachineThread, "StateMachine"))
27 , stateMachineSemaphore_ (toolbox::BSem::FULL)
28 //, theConfigurationManager_ (new ConfigurationManager)//(Singleton<ConfigurationManager>::getInstance()) //I always load the full config but if I want to load a partial configuration (new ConfigurationManager)
29 //, supervisorClass_ (getApplicationDescriptor()->getClassName())
30 //, supervisorClassNoNamespace_ (supervisorClass_.substr(supervisorClass_.find_last_of(":")+1, supervisorClass_.length()-supervisorClass_.find_last_of(":")))
31 , theRemoteWebUsers_ (this)
32 //, propertiesAreSetup_ (false)
33 {
34  INIT_MF("CoreSupervisorBase");
35 
36  __SUP_COUT__ << "Begin!" << std::endl;
37 
38  xgi::bind (this, &CoreSupervisorBase::defaultPageWrapper, "Default" );
39  xgi::bind (this, &CoreSupervisorBase::requestWrapper, "Request");
40 
41  xgi::bind (this, &CoreSupervisorBase::stateMachineXgiHandler, "StateMachineXgiHandler");
42 
43  xoap::bind(this, &CoreSupervisorBase::stateMachineStateRequest, "StateMachineStateRequest", XDAQ_NS_URI );
44  xoap::bind(this, &CoreSupervisorBase::stateMachineErrorMessageRequest, "StateMachineErrorMessageRequest", XDAQ_NS_URI );
45  //xoap::bind(this, &CoreSupervisorBase::macroMakerSupervisorRequest, "MacroMakerSupervisorRequest", XDAQ_NS_URI ); //moved to only FESupervisor!
46  xoap::bind(this, &CoreSupervisorBase::workLoopStatusRequestWrapper, "WorkLoopStatusRequest", XDAQ_NS_URI );
47 
48  return;
49 }
50 
51 //========================================================================================================================
52 CoreSupervisorBase::~CoreSupervisorBase(void)
53 {
54  destroy();
55 }
56 
57 //========================================================================================================================
58 void CoreSupervisorBase::destroy(void)
59 {
60  __SUP_COUT__ << "Destroying..." << std::endl;
61  for(auto& it: theStateMachineImplementation_)
62  delete it;
63  theStateMachineImplementation_.clear();
64 }
65 
66 //========================================================================================================================
67 //wrapper for inheritance call
68 void CoreSupervisorBase::defaultPageWrapper(xgi::Input * in, xgi::Output * out )
69 {
70  return defaultPage(in,out);
71 }
72 
73 //========================================================================================================================
74 void CoreSupervisorBase::defaultPage(xgi::Input * in, xgi::Output * out )
75 {
76  __SUP_COUT__<< "Supervisor class " << supervisorClass_ << std::endl;
77 
78  std::stringstream pagess;
79  pagess << "/WebPath/html/" <<
80  supervisorClassNoNamespace_ << ".html?urn=" <<
81  this->getApplicationDescriptor()->getLocalId();
82 
83  __SUP_COUT__<< "Default page = " << pagess.str() << std::endl;
84 
85  *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame src='" <<
86  pagess.str() <<
87  "'></frameset></html>";
88 }
89 
90 //========================================================================================================================
91 //requestWrapper ~
92 // wrapper for inheritance Supervisor request call
93 void CoreSupervisorBase::requestWrapper(xgi::Input * in, xgi::Output * out )
94 
95 {
96  //checkSupervisorPropertySetup();
97 
98  cgicc::Cgicc cgiIn(in);
99  std::string requestType = CgiDataUtilities::getData(cgiIn,"RequestType");
100 
101  //__SUP_COUT__ << "requestType " << requestType << " files: " << cgiIn.getFiles().size() << std::endl;
102 
103  HttpXmlDocument xmlOut;
104  WebUsers::RequestUserInfo userInfo(requestType,
105  CgiDataUtilities::getOrPostData(cgiIn,"CookieCode"));
106 
107  CorePropertySupervisorBase::getRequestUserInfo(userInfo);
108 
109  if(!theRemoteWebUsers_.xmlRequestToGateway(
110  cgiIn,
111  out,
112  &xmlOut,
113  CorePropertySupervisorBase::allSupervisorInfo_,
114  userInfo))
115  return; //access failed
116 
117 
118  //done checking cookieCode, sequence, userWithLock, and permissions access all in one shot!
119  //**** end LOGIN GATEWAY CODE ***//
120 
121  if(!userInfo.automatedCommand_)
122  __SUP_COUT__ << "requestType: " << requestType << __E__;
123 
124  if(userInfo.NonXMLRequestType_)
125  {
126  nonXmlRequest(requestType,cgiIn,*out,userInfo);
127  return;
128  }
129  //else xml request type
130 
131  request(requestType,cgiIn,xmlOut,userInfo);
132 
133  //report any errors encountered
134  {
135  unsigned int occurance = 0;
136  std::string err = xmlOut.getMatchingValue("Error",occurance++);
137  while(err != "")
138  {
139  __SUP_COUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err << std::endl;
140  __MOUT_ERR__ << "'" << requestType << "' ERROR encountered: " << err << std::endl;
141  err = xmlOut.getMatchingValue("Error",occurance++);
142  }
143  }
144 
145 
146  //return xml doc holding server response
147  xmlOut.outputXmlDocument((std::ostringstream*) out, false /*print to cout*/,
148  !userInfo.NoXmlWhiteSpace_/*allow whitespace*/);
149 
150 }
151 
152 //========================================================================================================================
153 //request
154 // Supervisors should override this function. It will be called after user access has been verified
155 // according to the Supervisor Property settings. The CoreSupervisorBase class provides consistent
156 // access, responses, and error handling across all inheriting supervisors that use ::request.
157 void CoreSupervisorBase::request(const std::string& requestType, cgicc::Cgicc& cgiIn, HttpXmlDocument& xmlOut,
158  const WebUsers::RequestUserInfo& userInfo)
159 {
160  __SUP_COUT__ << "This is the empty Core Supervisor request. Supervisors should override this function." << __E__;
161 
162 // KEEP:
163 // here are some possibly interesting example lines of code for overriding supervisors
164 //
165 //
166 // if(requestType == "savePlanCommandSequence")
167 // {
168 // std::string planName = CgiDataUtilities::getData(cgiIn,"planName"); //from GET
169 // std::string commands = CgiDataUtilities::postData(cgiIn,"commands"); //from POST
170 //
171 // cgiIn.getFiles()
172 // __SUP_COUT__ << "planName: " << planName << __E__;
173 // __SUP_COUTV__(commands);
174 //
175 //
176 // }
177 // else
178 // {
179 // __SUP_SS__ << "requestType '" << requestType << "' request not recognized." << std::endl;
180 // __SUP_COUT__ << "\n" << ss.str();
181 // xmlOut.addTextElementToData("Error", ss.str());
182 // }
183 // xmlOut.addTextElementToData("Error",
184 // "request encountered an error!");
185 }
186 
187 //========================================================================================================================
188 //nonXmlRequest
189 // Supervisors should override this function. It will be called after user access has been verified
190 // according to the Supervisor Property settings. The CoreSupervisorBase class provides consistent
191 // access, responses, and error handling across all inheriting supervisors that use ::request.
192 void CoreSupervisorBase::nonXmlRequest(const std::string& requestType, cgicc::Cgicc& cgiIn, std::ostream& out,
193  const WebUsers::RequestUserInfo& userInfo)
194 {
195  __SUP_COUT__ << "This is the empty Core Supervisor non-xml request. Supervisors should override this function." << __E__;
196  out << "This is the empty Core Supervisor non-xml request. Supervisors should override this function." << __E__;
197 }
198 
199 //========================================================================================================================
200 void CoreSupervisorBase::stateMachineXgiHandler(xgi::Input * in, xgi::Output * out )
201 
202 {}
203 
204 //========================================================================================================================
205 void CoreSupervisorBase::stateMachineResultXgiHandler(xgi::Input* in, xgi::Output* out )
206 
207 {}
208 
209 //========================================================================================================================
210 xoap::MessageReference CoreSupervisorBase::stateMachineXoapHandler(xoap::MessageReference message )
211 
212 {
213  __SUP_COUT__<< "Soap Handler!" << std::endl;
214  stateMachineWorkLoopManager_.removeProcessedRequests();
215  stateMachineWorkLoopManager_.processRequest(message);
216  __SUP_COUT__<< "Done - Soap Handler!" << std::endl;
217  return message;
218 }
219 
220 //========================================================================================================================
221 xoap::MessageReference CoreSupervisorBase::stateMachineResultXoapHandler(xoap::MessageReference message )
222 
223 {
224  __SUP_COUT__<< "Soap Handler!" << std::endl;
225  //stateMachineWorkLoopManager_.removeProcessedRequests();
226  //stateMachineWorkLoopManager_.processRequest(message);
227  __SUP_COUT__<< "Done - Soap Handler!" << std::endl;
228  return message;
229 }
230 
231 //========================================================================================================================
232 //indirection to allow for overriding handler
233 xoap::MessageReference CoreSupervisorBase::workLoopStatusRequestWrapper(xoap::MessageReference message)
234 
235 {
236  //this should have an override for monitoring work loops being done
237  return workLoopStatusRequest(message);
238 } //end workLoopStatusRequest()
239 
240 //========================================================================================================================
241 xoap::MessageReference CoreSupervisorBase::workLoopStatusRequest(xoap::MessageReference message)
242 
243 {
244  //this should have an override for monitoring work loops being done
245  return SOAPUtilities::makeSOAPMessageReference(CoreSupervisorBase::WORK_LOOP_DONE);
246 } //end workLoopStatusRequest()
247 
248 //========================================================================================================================
249 bool CoreSupervisorBase::stateMachineThread(toolbox::task::WorkLoop* workLoop)
250 {
251  stateMachineSemaphore_.take();
252  __SUP_COUT__<< "Re-sending message..." << SOAPUtilities::translate(stateMachineWorkLoopManager_.getMessage(workLoop)).getCommand() << std::endl;
253  std::string reply = send(this->getApplicationDescriptor(),stateMachineWorkLoopManager_.getMessage(workLoop));
254  stateMachineWorkLoopManager_.report(workLoop, reply, 100, true);
255  __SUP_COUT__<< "Done with message" << std::endl;
256  stateMachineSemaphore_.give();
257  return false;//execute once and automatically remove the workloop so in WorkLoopManager the try workLoop->remove(job_) could be commented out
258  //return true;//go on and then you must do the workLoop->remove(job_) in WorkLoopManager
259 }
260 
261 //========================================================================================================================
262 xoap::MessageReference CoreSupervisorBase::stateMachineStateRequest(xoap::MessageReference message)
263 
264 {
265  __SUP_COUT__<< "theStateMachine_.getCurrentStateName() = " << theStateMachine_.getCurrentStateName() << std::endl;
266  return SOAPUtilities::makeSOAPMessageReference(theStateMachine_.getCurrentStateName());
267 }
268 
269 //========================================================================================================================
270 xoap::MessageReference CoreSupervisorBase::stateMachineErrorMessageRequest(xoap::MessageReference message)
271 
272 {
273  __SUP_COUT__<< "theStateMachine_.getErrorMessage() = " << theStateMachine_.getErrorMessage() << std::endl;
274 
275  SOAPParameters retParameters;
276  retParameters.addParameter("ErrorMessage",theStateMachine_.getErrorMessage());
277  return SOAPUtilities::makeSOAPMessageReference("stateMachineErrorMessageRequestReply",retParameters);
278 }
279 
280 //========================================================================================================================
281 void CoreSupervisorBase::stateInitial(toolbox::fsm::FiniteStateMachine& fsm)
282 
283 {
284  __SUP_COUT__ << "CoreSupervisorBase::stateInitial" << std::endl;
285 }
286 
287 //========================================================================================================================
288 void CoreSupervisorBase::stateHalted(toolbox::fsm::FiniteStateMachine& fsm)
289 
290 {
291  __SUP_COUT__ << "CoreSupervisorBase::stateHalted" << std::endl;
292 }
293 
294 //========================================================================================================================
295 void CoreSupervisorBase::stateRunning(toolbox::fsm::FiniteStateMachine& fsm)
296 
297 {
298  __SUP_COUT__ << "CoreSupervisorBase::stateRunning" << std::endl;
299 }
300 
301 //========================================================================================================================
302 void CoreSupervisorBase::stateConfigured(toolbox::fsm::FiniteStateMachine& fsm)
303 
304 {
305  __SUP_COUT__ << "CoreSupervisorBase::stateConfigured" << std::endl;
306 }
307 
308 //========================================================================================================================
309 void CoreSupervisorBase::statePaused(toolbox::fsm::FiniteStateMachine& fsm)
310 
311 {
312  __SUP_COUT__ << "CoreSupervisorBase::statePaused" << std::endl;
313 }
314 
315 //========================================================================================================================
316 void CoreSupervisorBase::inError (toolbox::fsm::FiniteStateMachine & fsm)
317 
318 {
319  __SUP_COUT__<< "Fsm current state: " << theStateMachine_.getCurrentStateName()<< std::endl;
320  //rcmsStateNotifier_.stateChanged("Error", "");
321 }
322 
323 //========================================================================================================================
324 void CoreSupervisorBase::enteringError (toolbox::Event::Reference e)
325 
326 {
327  __SUP_COUT__<< "Fsm current state: " << theStateMachine_.getCurrentStateName()
328  << "\n\nError Message: " <<
329  theStateMachine_.getErrorMessage() << std::endl;
330  toolbox::fsm::FailedEvent& failedEvent = dynamic_cast<toolbox::fsm::FailedEvent&>(*e);
331  std::ostringstream error;
332  error << "Failure performing transition from "
333  << failedEvent.getFromState()
334  << " to "
335  << failedEvent.getToState()
336  << " exception: " << failedEvent.getException().what();
337  __SUP_COUT_ERR__<< error.str() << std::endl;
338  //diagService_->reportError(errstr.str(),DIAGERROR);
339 
340 }
341 
342 //========================================================================================================================
343 void CoreSupervisorBase::transitionConfiguring(toolbox::Event::Reference e)
344 
345 {
346  __SUP_COUT__ << "transitionConfiguring" << std::endl;
347 
348  std::pair<std::string /*group name*/, ConfigurationGroupKey> theGroup(
349  SOAPUtilities::translate(theStateMachine_.getCurrentMessage()).
350  getParameters().getValue("ConfigurationGroupName"),
351  ConfigurationGroupKey(SOAPUtilities::translate(theStateMachine_.getCurrentMessage()).
352  getParameters().getValue("ConfigurationGroupKey")));
353 
354  __SUP_COUT__ << "Configuration group name: " << theGroup.first << " key: " <<
355  theGroup.second << std::endl;
356 
357  theConfigurationManager_->loadConfigurationGroup(
358  theGroup.first,
359  theGroup.second, true);
360 
361  //Now that the configuration manager has all the necessary configurations, create all objects that depend on the configuration
362 
363  try
364  {
365  for(auto& it: theStateMachineImplementation_)
366  it->configure();
367  }
368  catch(const std::runtime_error& e)
369  {
370  __SUP_SS__ << "Error was caught while configuring: " << e.what() << std::endl;
371  __SUP_COUT_ERR__ << "\n" << ss.str();
372  theStateMachine_.setErrorMessage(ss.str());
373  throw toolbox::fsm::exception::Exception(
374  "Transition Error" /*name*/,
375  ss.str() /* message*/,
376  "CoreSupervisorBase::transitionConfiguring" /*module*/,
377  __LINE__ /*line*/,
378  __FUNCTION__ /*function*/
379  );
380  }
381 
382 }
383 
384 //========================================================================================================================
385 //transitionHalting
386 // Ignore errors if coming from Failed state
387 void CoreSupervisorBase::transitionHalting(toolbox::Event::Reference e)
388 
389 {
390  __SUP_COUT__ << "transitionHalting" << std::endl;
391 
392  for(auto& it: theStateMachineImplementation_)
393  {
394  try
395  {
396  it->halt();
397  }
398  catch(const std::runtime_error& e)
399  {
400  //if halting from Failed state, then ignore errors
401  if(theStateMachine_.getProvenanceStateName() ==
402  RunControlStateMachine::FAILED_STATE_NAME)
403  {
404  __SUP_COUT_INFO__ << "Error was caught while halting (but ignoring because previous state was '" <<
405  RunControlStateMachine::FAILED_STATE_NAME << "'): " << e.what() << std::endl;
406  }
407  else //if not previously in Failed state, then fail
408  {
409  __SUP_SS__ << "Error was caught while halting: " << e.what() << std::endl;
410  __SUP_COUT_ERR__ << "\n" << ss.str();
411  theStateMachine_.setErrorMessage(ss.str());
412  throw toolbox::fsm::exception::Exception(
413  "Transition Error" /*name*/,
414  ss.str() /* message*/,
415  "CoreSupervisorBase::transitionHalting" /*module*/,
416  __LINE__ /*line*/,
417  __FUNCTION__ /*function*/
418  );
419  }
420  }
421  }
422 }
423 
424 //========================================================================================================================
425 //Inheriting supervisor classes should not override this function, or should at least also call it in the override
426 // to maintain property functionality.
427 void CoreSupervisorBase::transitionInitializing(toolbox::Event::Reference e)
428 
429 {
430  __SUP_COUT__ << "transitionInitializing" << std::endl;
431 
432  CorePropertySupervisorBase::resetPropertiesAreSetup(); //indicate need to re-load user properties
433 
434 
435  //Note: Do not initialize the state machine implementations... do any initializing in configure
436  // This allows re-instantiation at each configure time.
437  //for(auto& it: theStateMachineImplementation_)
438  //it->initialize();
439 }
440 
441 //========================================================================================================================
442 void CoreSupervisorBase::transitionPausing(toolbox::Event::Reference e)
443 
444 {
445  __SUP_COUT__ << "transitionPausing" << std::endl;
446 
447  try
448  {
449  for(auto& it: theStateMachineImplementation_)
450  it->pause();
451  }
452  catch(const std::runtime_error& e)
453  {
454  __SUP_SS__ << "Error was caught while pausing: " << e.what() << std::endl;
455  __SUP_COUT_ERR__ << "\n" << ss.str();
456  theStateMachine_.setErrorMessage(ss.str());
457  throw toolbox::fsm::exception::Exception(
458  "Transition Error" /*name*/,
459  ss.str() /* message*/,
460  "CoreSupervisorBase::transitionPausing" /*module*/,
461  __LINE__ /*line*/,
462  __FUNCTION__ /*function*/
463  );
464  }
465 }
466 
467 //========================================================================================================================
468 void CoreSupervisorBase::transitionResuming(toolbox::Event::Reference e)
469 
470 {
471  //NOTE: I want to first start the data manager first if this is a FEDataManagerSupervisor
472 
473 
474  __SUP_COUT__ << "transitionResuming" << std::endl;
475 
476  try
477  {
478  for(auto& it: theStateMachineImplementation_)
479  it->resume();
480  }
481  catch(const std::runtime_error& e)
482  {
483  __SUP_SS__ << "Error was caught while resuming: " << e.what() << std::endl;
484  __SUP_COUT_ERR__ << "\n" << ss.str();
485  theStateMachine_.setErrorMessage(ss.str());
486  throw toolbox::fsm::exception::Exception(
487  "Transition Error" /*name*/,
488  ss.str() /* message*/,
489  "CoreSupervisorBase::transitionResuming" /*module*/,
490  __LINE__ /*line*/,
491  __FUNCTION__ /*function*/
492  );
493  }
494 }
495 
496 //========================================================================================================================
497 void CoreSupervisorBase::transitionStarting(toolbox::Event::Reference e)
498 
499 {
500 
501  //NOTE: I want to first start the data manager first if this is a FEDataManagerSupervisor
502 
503  __SUP_COUT__ << "transitionStarting" << std::endl;
504 
505  try
506  {
507  for(auto& it: theStateMachineImplementation_)
508  it->start(SOAPUtilities::translate(theStateMachine_.getCurrentMessage()).getParameters().getValue("RunNumber"));
509  }
510  catch(const std::runtime_error& e)
511  {
512  __SUP_SS__ << "Error was caught while starting: " << e.what() << std::endl;
513  __SUP_COUT_ERR__ << "\n" << ss.str();
514  theStateMachine_.setErrorMessage(ss.str());
515  throw toolbox::fsm::exception::Exception(
516  "Transition Error" /*name*/,
517  ss.str() /* message*/,
518  "CoreSupervisorBase::transitionStarting" /*module*/,
519  __LINE__ /*line*/,
520  __FUNCTION__ /*function*/
521  );
522  }
523 }
524 
525 //========================================================================================================================
526 void CoreSupervisorBase::transitionStopping(toolbox::Event::Reference e)
527 
528 {
529  __SUP_COUT__ << "transitionStopping" << std::endl;
530 
531  try
532  {
533  for(auto& it: theStateMachineImplementation_)
534  it->stop();
535  }
536  catch(const std::runtime_error& e)
537  {
538  __SUP_SS__ << "Error was caught while pausing: " << e.what() << std::endl;
539  __SUP_COUT_ERR__ << "\n" << ss.str();
540  theStateMachine_.setErrorMessage(ss.str());
541  throw toolbox::fsm::exception::Exception(
542  "Transition Error" /*name*/,
543  ss.str() /* message*/,
544  "CoreSupervisorBase::transitionStopping" /*module*/,
545  __LINE__ /*line*/,
546  __FUNCTION__ /*function*/
547  );
548  }
549 }