otsdaq  v2_00_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 throw (xdaq::exception::Exception)
21 : xdaq::Application (s)
22 , SOAPMessenger (this)
23 , stateMachineWorkLoopManager_ (toolbox::task::bind(this, &CoreSupervisorBase::stateMachineThread, "StateMachine"))
24 , stateMachineSemaphore_ (toolbox::BSem::FULL)
25 , theConfigurationManager_ (new ConfigurationManager)//(Singleton<ConfigurationManager>::getInstance()) //I always load the full config but if I want to load a partial configuration (new ConfigurationManager)
26 , XDAQContextConfigurationName_ (theConfigurationManager_->__GET_CONFIG__(XDAQContextConfiguration)->getConfigurationName())
27 , supervisorConfigurationPath_ ("INITIALIZED INSIDE THE CONTRUCTOR BECAUSE IT NEEDS supervisorContextUID_ and supervisorApplicationUID_")
28 , supervisorContextUID_ ("INITIALIZED INSIDE THE CONTRUCTOR TO LAUNCH AN EXCEPTION")
29 , supervisorApplicationUID_ ("INITIALIZED INSIDE THE CONTRUCTOR TO LAUNCH AN EXCEPTION")
30 , supervisorClass_ (getApplicationDescriptor()->getClassName())
31 , supervisorClassNoNamespace_ (supervisorClass_.substr(supervisorClass_.find_last_of(":")+1, supervisorClass_.length()-supervisorClass_.find_last_of(":")))
32 , theRemoteWebUsers_ (this)
33 , LOCK_REQUIRED_ (false) //set default
34 , USER_PERMISSIONS_THRESHOLD_ (1) //set default
35 {
36  INIT_MF("CoreSupervisorBase");
37 
38  __COUT__ << "Begin!" << std::endl;
39 
40  xgi::bind (this, &CoreSupervisorBase::DefaultWrapper, "Default" );
41  xgi::bind (this, &CoreSupervisorBase::requestWrapper, "Request");
42  xgi::bind (this, &CoreSupervisorBase::stateMachineXgiHandler, "StateMachineXgiHandler");
43 
44  xoap::bind(this, &CoreSupervisorBase::stateMachineStateRequest, "StateMachineStateRequest", XDAQ_NS_URI );
45  xoap::bind(this, &CoreSupervisorBase::stateMachineErrorMessageRequest, "StateMachineErrorMessageRequest", XDAQ_NS_URI );
46  //xoap::bind(this, &CoreSupervisorBase::macroMakerSupervisorRequest, "MacroMakerSupervisorRequest", XDAQ_NS_URI );
47  xoap::bind(this, &CoreSupervisorBase::workLoopStatusRequestWrapper, "WorkLoopStatusRequest", XDAQ_NS_URI );
48 
49  try
50  {
51  supervisorContextUID_ = theConfigurationManager_->__GET_CONFIG__(XDAQContextConfiguration)->getContextUID(
52  getApplicationContext()->getContextDescriptor()->getURL());
53  }
54  catch(...)
55  {
56  __COUT_ERR__ << "XDAQ Supervisor could not access it's configuration through the Configuration Context Group." <<
57  " The XDAQContextConfigurationName = " << XDAQContextConfigurationName_ <<
58  ". The supervisorApplicationUID = " << supervisorApplicationUID_ << std::endl;
59  throw;
60  }
61  try
62  {
63  supervisorApplicationUID_ = theConfigurationManager_->__GET_CONFIG__(XDAQContextConfiguration)->getApplicationUID
64  (
65  getApplicationContext()->getContextDescriptor()->getURL(),
66  getApplicationDescriptor()->getLocalId()
67  );
68  }
69  catch(...)
70  {
71  __COUT_ERR__ << "XDAQ Supervisor could not access it's configuration through the Configuration Application Group."
72  << " The supervisorApplicationUID = " << supervisorApplicationUID_ << std::endl;
73  throw;
74  }
75  supervisorConfigurationPath_ = "/" + supervisorContextUID_ + "/LinkToApplicationConfiguration/" + supervisorApplicationUID_ + "/LinkToSupervisorConfiguration";
76 
77  setStateMachineName(supervisorApplicationUID_);
78 
79  allSupervisorInfo_.init(getApplicationContext());
80  __COUT__ << "Name = " << allSupervisorInfo_.getSupervisorInfo(this).getName();
81 
82 
83  __COUT__ << "Initializing..." << std::endl;
84 
85  setSupervisorPropertyDefaults(); //calls virtual init (where default supervisor properties should be set)
86 
87  //try to get security settings
88  {
89 
90  __COUT__ << "Looking for " <<
91  supervisorContextUID_ << "/" << supervisorApplicationUID_ <<
92  " supervisor security settings..." << __E__;
93 
94  ConfigurationTree appNode = theConfigurationManager_->getSupervisorNode(
95  supervisorContextUID_, supervisorApplicationUID_);
96  try
97  {
98  auto /*map<name,node>*/ children = appNode.getNode("LinkToPropertyConfiguration").getChildren();
99 
100  for(auto& child:children)
101  {
102  if(child.second.getNode("Status").getValue<bool>() == false) continue; //skip OFF properties
103 
104  auto propertyName = child.second.getNode("PropertyName");
105 
106  if(propertyName.getValue() ==
107  supervisorProperties_.fieldRequireLock)
108  {
109  LOCK_REQUIRED_ = child.second.getNode("PropertyValue").getValue<bool>();
110  __COUTV__(LOCK_REQUIRED_);
111  }
112  else if(propertyName.getValue() ==
113  supervisorProperties_.fieldUserPermissionsThreshold)
114  {
115  USER_PERMISSIONS_THRESHOLD_ = child.second.getNode("PropertyValue").getValue<uint8_t>();
116  __COUTV__(USER_PERMISSIONS_THRESHOLD_);
117  }
118  }
119  }
120  catch(...)
121  {
122  __COUT__ << "No supervisor security settings found, going with defaults." << __E__;
123  }
124  }
125 }
126 
127 //========================================================================================================================
128 CoreSupervisorBase::~CoreSupervisorBase(void)
129 {
130  destroy();
131 }
132 
133 //========================================================================================================================
134 //When overriding, setup default property values here
135 // called by CoreSupervisorBase constructor before loading user defined property values
136 void CoreSupervisorBase::setSupervisorPropertyDefaults(void)
137 {
138  //This can be done in the constructor because when you start xdaq it loads the configuration that can't be changed while running!
139 
140  __COUT__ << "Using base class property defaults..." << std::endl;
141 
142  LOCK_REQUIRED_ = false; //set default
143  USER_PERMISSIONS_THRESHOLD_ = 1; //set default
144  USER_GROUPS_ALLOWED_ = ""; //set default
145  USER_GROUPS_DISALLOWED_ = ""; //set default
146 
147  __COUTV__(LOCK_REQUIRED_);
148  __COUTV__(USER_PERMISSIONS_THRESHOLD_);
149  __COUTV__(USER_GROUPS_ALLOWED_);
150  __COUTV__(USER_GROUPS_DISALLOWED_);
151 }
152 
153 //========================================================================================================================
154 void CoreSupervisorBase::destroy(void)
155 {
156  __COUT__ << "Destroying..." << std::endl;
157  for(auto& it: theStateMachineImplementation_)
158  delete it;
159  theStateMachineImplementation_.clear();
160 }
161 
162 //========================================================================================================================
163 //wrapper for inheritance call
164 void CoreSupervisorBase::DefaultWrapper(xgi::Input * in, xgi::Output * out )
165 throw (xgi::exception::Exception)
166 {
167  return Default(in,out);
168 }
169 
170 //========================================================================================================================
171 void CoreSupervisorBase::Default(xgi::Input * in, xgi::Output * out )
172 throw (xgi::exception::Exception)
173 {
174  __COUT__<< "Supervisor class " << supervisorClass_ << std::endl;
175 
176  std::stringstream pagess;
177  pagess << "/WebPath/html/" <<
178  supervisorClassNoNamespace_ << ".html?urn=" <<
179  this->getApplicationDescriptor()->getLocalId();
180 
181  __COUT__<< "Default page = " << pagess.str() << std::endl;
182 
183  *out << "<!DOCTYPE HTML><html lang='en'><frameset col='100%' row='100%'><frame src='" <<
184  pagess.str() <<
185  "'></frameset></html>";
186 }
187 
188 //========================================================================================================================
189 //wrapper for inheritance call
190 void CoreSupervisorBase::requestWrapper(xgi::Input * in, xgi::Output * out )
191 throw (xgi::exception::Exception)
192 {
193  return request(in,out);
194 }
195 
196 //========================================================================================================================
197 void CoreSupervisorBase::request(xgi::Input * in, xgi::Output * out )
198 throw (xgi::exception::Exception)
199 {
200 //
201 //
202 // cgicc::Cgicc cgi(in);
203 // std::string write = CgiDataUtilities::getOrPostData(cgi,"write");
204 // std::string addr = CgiDataUtilities::getOrPostData(cgi,"addr");
205 // std::string data = CgiDataUtilities::getOrPostData(cgi,"data");
206 //
207 // __COUT__<< "write " << write << " addr: " << addr << " data: " << data << std::endl;
208 //
209 // unsigned long long int addr64,data64;
210 // sscanf(addr.c_str(),"%llu",&addr64);
211 // sscanf(data.c_str(),"%llu",&data64);
212 // __COUT__<< "write " << write << " addr: " << addr64 << " data: " << data64 << std::endl;
213 //
214 // *out << "done";
215 }
216 
217 //========================================================================================================================
218 void CoreSupervisorBase::stateMachineXgiHandler(xgi::Input * in, xgi::Output * out )
219 throw (xgi::exception::Exception)
220 {}
221 
222 //========================================================================================================================
223 void CoreSupervisorBase::stateMachineResultXgiHandler(xgi::Input* in, xgi::Output* out )
224 throw (xgi::exception::Exception)
225 {}
226 
227 //========================================================================================================================
228 xoap::MessageReference CoreSupervisorBase::stateMachineXoapHandler(xoap::MessageReference message )
229 throw (xoap::exception::Exception)
230 {
231  __COUT__<< "Soap Handler!" << std::endl;
232  stateMachineWorkLoopManager_.removeProcessedRequests();
233  stateMachineWorkLoopManager_.processRequest(message);
234  __COUT__<< "Done - Soap Handler!" << std::endl;
235  return message;
236 }
237 
238 //========================================================================================================================
239 xoap::MessageReference CoreSupervisorBase::stateMachineResultXoapHandler(xoap::MessageReference message )
240 throw (xoap::exception::Exception)
241 {
242  __COUT__<< "Soap Handler!" << std::endl;
243  //stateMachineWorkLoopManager_.removeProcessedRequests();
244  //stateMachineWorkLoopManager_.processRequest(message);
245  __COUT__<< "Done - Soap Handler!" << std::endl;
246  return message;
247 }
248 
249 //========================================================================================================================
250 //indirection to allow for overriding handler
251 xoap::MessageReference CoreSupervisorBase::workLoopStatusRequestWrapper(xoap::MessageReference message)
252 throw (xoap::exception::Exception)
253 {
254  //this should have an override for monitoring work loops being done
255  return workLoopStatusRequest(message);
256 } //end workLoopStatusRequest()
257 
258 //========================================================================================================================
259 xoap::MessageReference CoreSupervisorBase::workLoopStatusRequest(xoap::MessageReference message)
260 throw (xoap::exception::Exception)
261 {
262  //this should have an override for monitoring work loops being done
263  return SOAPUtilities::makeSOAPMessageReference(CoreSupervisorBase::WORK_LOOP_DONE);
264 } //end workLoopStatusRequest()
265 
266 //========================================================================================================================
267 bool CoreSupervisorBase::stateMachineThread(toolbox::task::WorkLoop* workLoop)
268 {
269  stateMachineSemaphore_.take();
270  __COUT__<< "Re-sending message..." << SOAPUtilities::translate(stateMachineWorkLoopManager_.getMessage(workLoop)).getCommand() << std::endl;
271  std::string reply = send(this->getApplicationDescriptor(),stateMachineWorkLoopManager_.getMessage(workLoop));
272  stateMachineWorkLoopManager_.report(workLoop, reply, 100, true);
273  __COUT__<< "Done with message" << std::endl;
274  stateMachineSemaphore_.give();
275  return false;//execute once and automatically remove the workloop so in WorkLoopManager the try workLoop->remove(job_) could be commented out
276  //return true;//go on and then you must do the workLoop->remove(job_) in WorkLoopManager
277 }
278 
279 //========================================================================================================================
280 xoap::MessageReference CoreSupervisorBase::stateMachineStateRequest(xoap::MessageReference message)
281 throw (xoap::exception::Exception)
282 {
283  __COUT__<< "theStateMachine_.getCurrentStateName() = " << theStateMachine_.getCurrentStateName() << std::endl;
284  return SOAPUtilities::makeSOAPMessageReference(theStateMachine_.getCurrentStateName());
285 }
286 
287 //========================================================================================================================
288 xoap::MessageReference CoreSupervisorBase::stateMachineErrorMessageRequest(xoap::MessageReference message)
289 throw (xoap::exception::Exception)
290 {
291  __COUT__<< "theStateMachine_.getErrorMessage() = " << theStateMachine_.getErrorMessage() << std::endl;
292 
293  SOAPParameters retParameters;
294  retParameters.addParameter("ErrorMessage",theStateMachine_.getErrorMessage());
295  return SOAPUtilities::makeSOAPMessageReference("stateMachineErrorMessageRequestReply",retParameters);
296 }
297 
298 //========================================================================================================================
299 void CoreSupervisorBase::stateInitial(toolbox::fsm::FiniteStateMachine& fsm)
300 throw (toolbox::fsm::exception::Exception)
301 {
302  __COUT__ << "CoreSupervisorBase::stateInitial" << std::endl;
303 }
304 
305 //========================================================================================================================
306 void CoreSupervisorBase::stateHalted(toolbox::fsm::FiniteStateMachine& fsm)
307 throw (toolbox::fsm::exception::Exception)
308 {
309  __COUT__ << "CoreSupervisorBase::stateHalted" << std::endl;
310 }
311 
312 //========================================================================================================================
313 void CoreSupervisorBase::stateRunning(toolbox::fsm::FiniteStateMachine& fsm)
314 throw (toolbox::fsm::exception::Exception)
315 {
316  __COUT__ << "CoreSupervisorBase::stateRunning" << std::endl;
317 }
318 
319 //========================================================================================================================
320 void CoreSupervisorBase::stateConfigured(toolbox::fsm::FiniteStateMachine& fsm)
321 throw (toolbox::fsm::exception::Exception)
322 {
323  __COUT__ << "CoreSupervisorBase::stateConfigured" << std::endl;
324 }
325 
326 //========================================================================================================================
327 void CoreSupervisorBase::statePaused(toolbox::fsm::FiniteStateMachine& fsm)
328 throw (toolbox::fsm::exception::Exception)
329 {
330  __COUT__ << "CoreSupervisorBase::statePaused" << std::endl;
331 }
332 
333 //========================================================================================================================
334 void CoreSupervisorBase::inError (toolbox::fsm::FiniteStateMachine & fsm)
335 throw (toolbox::fsm::exception::Exception)
336 {
337  __COUT__<< "Fsm current state: " << theStateMachine_.getCurrentStateName()<< std::endl;
338  //rcmsStateNotifier_.stateChanged("Error", "");
339 }
340 
341 //========================================================================================================================
342 void CoreSupervisorBase::enteringError (toolbox::Event::Reference e)
343 throw (toolbox::fsm::exception::Exception)
344 {
345  __COUT__<< "Fsm current state: " << theStateMachine_.getCurrentStateName()
346  << "\n\nError Message: " <<
347  theStateMachine_.getErrorMessage() << std::endl;
348  toolbox::fsm::FailedEvent& failedEvent = dynamic_cast<toolbox::fsm::FailedEvent&>(*e);
349  std::ostringstream error;
350  error << "Failure performing transition from "
351  << failedEvent.getFromState()
352  << " to "
353  << failedEvent.getToState()
354  << " exception: " << failedEvent.getException().what();
355  __COUT_ERR__<< error.str() << std::endl;
356  //diagService_->reportError(errstr.str(),DIAGERROR);
357 
358 }
359 
360 //========================================================================================================================
361 void CoreSupervisorBase::transitionConfiguring(toolbox::Event::Reference e)
362 throw (toolbox::fsm::exception::Exception)
363 {
364  __COUT__ << "transitionConfiguring" << std::endl;
365 
366  std::pair<std::string /*group name*/, ConfigurationGroupKey> theGroup(
367  SOAPUtilities::translate(theStateMachine_.getCurrentMessage()).
368  getParameters().getValue("ConfigurationGroupName"),
369  ConfigurationGroupKey(SOAPUtilities::translate(theStateMachine_.getCurrentMessage()).
370  getParameters().getValue("ConfigurationGroupKey")));
371 
372  __COUT__ << "Configuration group name: " << theGroup.first << " key: " <<
373  theGroup.second << std::endl;
374 
375  theConfigurationManager_->loadConfigurationGroup(
376  theGroup.first,
377  theGroup.second, true);
378 
379 
380  //Now that the configuration manager has all the necessary configurations I can create all objects dependent of the configuration
381 
382  try
383  {
384  for(auto& it: theStateMachineImplementation_)
385  it->configure();
386  }
387  catch(const std::runtime_error& e)
388  {
389  __SS__ << "Error was caught while configuring: " << e.what() << std::endl;
390  __COUT_ERR__ << "\n" << ss.str();
391  theStateMachine_.setErrorMessage(ss.str());
392  throw toolbox::fsm::exception::Exception(
393  "Transition Error" /*name*/,
394  ss.str() /* message*/,
395  "CoreSupervisorBase::transitionConfiguring" /*module*/,
396  __LINE__ /*line*/,
397  __FUNCTION__ /*function*/
398  );
399  }
400 
401 }
402 
403 //========================================================================================================================
404 //transitionHalting
405 // Ignore errors if coming from Failed state
406 void CoreSupervisorBase::transitionHalting(toolbox::Event::Reference e)
407 throw (toolbox::fsm::exception::Exception)
408 {
409  __COUT__ << "transitionHalting" << std::endl;
410 
411  for(auto& it: theStateMachineImplementation_)
412  {
413  try
414  {
415  it->halt();
416  }
417  catch(const std::runtime_error& e)
418  {
419  //if halting from Failed state, then ignore errors
420  if(theStateMachine_.getProvenanceStateName() ==
421  RunControlStateMachine::FAILED_STATE_NAME)
422  {
423  __COUT_INFO__ << "Error was caught while halting (but ignoring because previous state was '" <<
424  RunControlStateMachine::FAILED_STATE_NAME << "'): " << e.what() << std::endl;
425  }
426  else //if not previously in Failed state, then fail
427  {
428  __SS__ << "Error was caught while halting: " << e.what() << std::endl;
429  __COUT_ERR__ << "\n" << ss.str();
430  theStateMachine_.setErrorMessage(ss.str());
431  throw toolbox::fsm::exception::Exception(
432  "Transition Error" /*name*/,
433  ss.str() /* message*/,
434  "CoreSupervisorBase::transitionHalting" /*module*/,
435  __LINE__ /*line*/,
436  __FUNCTION__ /*function*/
437  );
438  }
439  }
440  }
441 }
442 
443 //========================================================================================================================
444 void CoreSupervisorBase::transitionInitializing(toolbox::Event::Reference e)
445 throw (toolbox::fsm::exception::Exception)
446 {
447  __COUT__ << "transitionInitializing" << std::endl;
448 
449  // for(auto& it: theStateMachineImplementation_)
450  //it->initialize();
451 }
452 
453 //========================================================================================================================
454 void CoreSupervisorBase::transitionPausing(toolbox::Event::Reference e)
455 throw (toolbox::fsm::exception::Exception)
456 {
457  __COUT__ << "transitionPausing" << std::endl;
458 
459  try
460  {
461  for(auto& it: theStateMachineImplementation_)
462  it->pause();
463  }
464  catch(const std::runtime_error& e)
465  {
466  __SS__ << "Error was caught while pausing: " << e.what() << std::endl;
467  __COUT_ERR__ << "\n" << ss.str();
468  theStateMachine_.setErrorMessage(ss.str());
469  throw toolbox::fsm::exception::Exception(
470  "Transition Error" /*name*/,
471  ss.str() /* message*/,
472  "CoreSupervisorBase::transitionPausing" /*module*/,
473  __LINE__ /*line*/,
474  __FUNCTION__ /*function*/
475  );
476  }
477 }
478 
479 //========================================================================================================================
480 void CoreSupervisorBase::transitionResuming(toolbox::Event::Reference e)
481 throw (toolbox::fsm::exception::Exception)
482 {
483  //NOTE: I want to first start the data manager first if this is a FEDataManagerSupervisor
484 
485 
486  __COUT__ << "transitionResuming" << std::endl;
487 
488  try
489  {
490  for(auto& it: theStateMachineImplementation_)
491  it->resume();
492  }
493  catch(const std::runtime_error& e)
494  {
495  __SS__ << "Error was caught while resuming: " << e.what() << std::endl;
496  __COUT_ERR__ << "\n" << ss.str();
497  theStateMachine_.setErrorMessage(ss.str());
498  throw toolbox::fsm::exception::Exception(
499  "Transition Error" /*name*/,
500  ss.str() /* message*/,
501  "CoreSupervisorBase::transitionResuming" /*module*/,
502  __LINE__ /*line*/,
503  __FUNCTION__ /*function*/
504  );
505  }
506 }
507 
508 //========================================================================================================================
509 void CoreSupervisorBase::transitionStarting(toolbox::Event::Reference e)
510 throw (toolbox::fsm::exception::Exception)
511 {
512 
513  //NOTE: I want to first start the data manager first if this is a FEDataManagerSupervisor
514 
515  __COUT__ << "transitionStarting" << std::endl;
516 
517  try
518  {
519  for(auto& it: theStateMachineImplementation_)
520  it->start(SOAPUtilities::translate(theStateMachine_.getCurrentMessage()).getParameters().getValue("RunNumber"));
521  }
522  catch(const std::runtime_error& e)
523  {
524  __SS__ << "Error was caught while starting: " << e.what() << std::endl;
525  __COUT_ERR__ << "\n" << ss.str();
526  theStateMachine_.setErrorMessage(ss.str());
527  throw toolbox::fsm::exception::Exception(
528  "Transition Error" /*name*/,
529  ss.str() /* message*/,
530  "CoreSupervisorBase::transitionStarting" /*module*/,
531  __LINE__ /*line*/,
532  __FUNCTION__ /*function*/
533  );
534  }
535 }
536 
537 //========================================================================================================================
538 void CoreSupervisorBase::transitionStopping(toolbox::Event::Reference e)
539 throw (toolbox::fsm::exception::Exception)
540 {
541  __COUT__ << "transitionStopping" << std::endl;
542 
543  try
544  {
545  for(auto& it: theStateMachineImplementation_)
546  it->stop();
547  }
548  catch(const std::runtime_error& e)
549  {
550  __SS__ << "Error was caught while pausing: " << e.what() << std::endl;
551  __COUT_ERR__ << "\n" << ss.str();
552  theStateMachine_.setErrorMessage(ss.str());
553  throw toolbox::fsm::exception::Exception(
554  "Transition Error" /*name*/,
555  ss.str() /* message*/,
556  "CoreSupervisorBase::transitionStopping" /*module*/,
557  __LINE__ /*line*/,
558  __FUNCTION__ /*function*/
559  );
560  }
561 }