tdaq-develop-2025-02-12
Iterator.cc
1 #include "otsdaq/GatewaySupervisor/Iterator.h"
2 #include "otsdaq/CoreSupervisors/CoreSupervisorBase.h"
3 #include "otsdaq/GatewaySupervisor/GatewaySupervisor.h"
4 #include "otsdaq/Macros/CoutMacros.h"
5 #include "otsdaq/MessageFacility/MessageFacility.h"
6 #include "otsdaq/WebUsersUtilities/WebUsers.h"
7 
8 #include <iostream>
9 #include <thread> //for std::thread
10 
11 #undef __MF_SUBJECT__
12 #define __MF_SUBJECT__ "Iterator"
13 
14 using namespace ots;
15 
16 #define ITERATOR_PLAN_HISTORY_FILENAME \
17  ((getenv("SERVICE_DATA_PATH") == NULL) \
18  ? (std::string(__ENV__("USER_DATA")) + "/ServiceData") \
19  : (std::string(__ENV__("SERVICE_DATA_PATH")))) + \
20  "/IteratorPlanHistory.hist"
21 
22 const std::string Iterator::RESERVED_GEN_PLAN_NAME = "---GENERATED_PLAN---";
23 
24 //==============================================================================
25 Iterator::Iterator(GatewaySupervisor* supervisor)
26  : workloopRunning_(false)
27  , activePlanIsRunning_(false)
28  , iteratorBusy_(false)
29  , commandPlay_(false)
30  , commandPause_(false)
31  , commandHalt_(false)
32  , activePlanName_("")
33  , activeCommandIndex_(-1)
34  , activeCommandStartTime_(0)
35  , theSupervisor_(supervisor)
36 {
37  __COUT__ << "Iterator constructed." << __E__;
38 
39  //restore lastStartedPlanName_ and lastFinishedPlanName_ from file
40  __COUT__ << "Filename for iterator history: " << ITERATOR_PLAN_HISTORY_FILENAME
41  << __E__;
42  FILE* fp = fopen((ITERATOR_PLAN_HISTORY_FILENAME).c_str(), "r");
43  if(fp) // check for all core table names in file, and force their presence
44  {
45  char line[100];
46  int i = 0;
47  while(fgets(line, 100, fp))
48  {
49  if(strlen(line) < 3)
50  continue;
51  line[strlen(line) - 1] = '\0'; // remove endline
52  __COUTV__(line);
53  if(i == 0)
54  lastStartedPlanName_ = line;
55  else if(i == 1)
56  {
57  lastFinishedPlanName_ = line;
58  break; //only 2 lines in file (for now)
59  }
60  ++i;
61  }
62  fclose(fp);
63  __COUTV__(lastStartedPlanName_);
64  __COUTV__(lastFinishedPlanName_);
65  } //end get iterator plan history
66 } //end constructor()
67 
68 //==============================================================================
69 Iterator::~Iterator(void) {}
70 
71 //==============================================================================
72 void Iterator::IteratorWorkLoop(Iterator* iterator)
73 try
74 {
75  __COUT__ << "Iterator work loop starting..." << __E__;
76 
77  // mutex init scope
78  {
79  // lockout the messages array for the remainder of the scope
80  // this guarantees the reading thread can safely access the messages
81  if(iterator->theSupervisor_->VERBOSE_MUTEX)
82  __COUT__ << "Waiting for iterator access" << __E__;
83  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
84  if(iterator->theSupervisor_->VERBOSE_MUTEX)
85  __COUT__ << "Have iterator access" << __E__;
86 
87  iterator->errorMessage_ = ""; // clear error message
88  }
89 
90  ConfigurationManagerRW theConfigurationManager(
91  WebUsers::DEFAULT_ITERATOR_USERNAME); // this is a restricted username
92  // theConfigurationManager.init();
93  theConfigurationManager.getAllTableInfo(true /* refresh */, // to prep all info
94  0 /* accumulatedWarnings */,
95  "" /* errorFilterName */,
96  false /* getGroupKeys */,
97  false /* getGroupInfo */,
98  true /* initializeActiveGroups */);
99 
100  __COUT__ << "Iterator work loop starting..." << __E__;
101  IteratorWorkLoopStruct theIteratorStruct(iterator, &theConfigurationManager);
102  __COUT__ << "Iterator work loop starting..." << __E__;
103 
104  const IterateTable* itConfig;
105 
106  std::vector<IterateTable::Command> commands;
107 
108  try
109  {
110  while(1)
111  {
112  // Process:
113  // - always "listen" for commands
114  // - play: if no plan running, activePlanIsRunning_ = true,
115  // and start or continue plan based on name/commandIndex
116  // - pause: if plan playing, pause it, activePlanIsRunning_ = false
117  // and do not clear commandIndex or name, iteratorBusy_ = true
118  // - halt: if plan playing or not, activePlanIsRunning_ = false
119  // and clear commandIndex or name, iteratorBusy_ = false
120  // - when running
121  // - go through each command
122  // - start the command, commandBusy = true
123  // - check for complete, then commandBusy = false
124 
125  // start command handling
126  // define mutex scope
127  {
128  // lockout the messages array for the remainder of the scope
129  // this guarantees the reading thread can safely access the messages
130  if(iterator->theSupervisor_->VERBOSE_MUTEX)
131  __COUT__ << "Waiting for iterator access" << __E__;
132  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
133  if(iterator->theSupervisor_->VERBOSE_MUTEX)
134  __COUT__ << "Have iterator access" << __E__;
135 
136  if(iterator->commandPlay_)
137  {
138  iterator->commandPlay_ = false; // clear
139 
140  if(!iterator->activePlanIsRunning_)
141  {
142  // valid PLAY command!
143 
144  iterator->activePlanIsRunning_ = true;
145  iterator->iteratorBusy_ = true;
146 
147  if(theIteratorStruct.activePlan_ != iterator->activePlanName_)
148  {
149  __COUT__ << "New plan name encountered old="
150  << theIteratorStruct.activePlan_
151  << " vs new=" << iterator->activePlanName_ << __E__;
152  theIteratorStruct.commandIndex_ = -1; // reset for new plan
153  }
154 
155  theIteratorStruct.activePlan_ = iterator->activePlanName_;
156  iterator->lastStartedPlanName_ = iterator->activePlanName_;
157  FILE* fp = fopen((ITERATOR_PLAN_HISTORY_FILENAME).c_str(), "w");
158  if(fp)
159  {
160  fprintf(fp, "%s\n", iterator->lastStartedPlanName_.c_str());
161  fprintf(fp, "%s\n", iterator->lastFinishedPlanName_.c_str());
162  fclose(fp);
163  }
164  else
165  __COUT_WARN__ << "Could not open Iterator history file: "
166  << ITERATOR_PLAN_HISTORY_FILENAME << __E__;
167 
168  if(theIteratorStruct.commandIndex_ == (unsigned int)-1)
169  {
170  __COUT__ << "Starting plan '" << theIteratorStruct.activePlan_
171  << ".'" << __E__;
172  __COUT__ << "Starting plan '" << theIteratorStruct.activePlan_
173  << ".'" << __E__;
174  }
175  else
176  {
177  theIteratorStruct.doResumeAction_ = true;
178  __COUT__ << "Continuing plan '"
179  << theIteratorStruct.activePlan_
180  << "' at command index "
181  << theIteratorStruct.commandIndex_ << ". " << __E__;
182  __COUT__ << "Continuing plan '"
183  << theIteratorStruct.activePlan_
184  << "' at command index "
185  << theIteratorStruct.commandIndex_ << ". " << __E__;
186  }
187  }
188  }
189  else if(iterator->commandPause_ && !theIteratorStruct.doPauseAction_)
190  {
191  theIteratorStruct.doPauseAction_ = true;
192  iterator->commandPause_ = false; // clear
193  }
194  else if(iterator->commandHalt_ && !theIteratorStruct.doHaltAction_)
195  {
196  theIteratorStruct.doHaltAction_ = true;
197  iterator->commandHalt_ = false; // clear
198  }
199 
200  theIteratorStruct.running_ = iterator->activePlanIsRunning_;
201 
202  if(iterator
203  ->activeCommandIndex_ != // update active command status if changed
204  theIteratorStruct.commandIndex_)
205  {
206  iterator->activeCommandIndex_ = theIteratorStruct.commandIndex_;
207  if(theIteratorStruct.commandIndex_ <
208  theIteratorStruct.commands_.size())
209  iterator->activeCommandType_ =
210  theIteratorStruct.commands_[theIteratorStruct.commandIndex_]
211  .type_;
212  else
213  iterator->activeCommandType_ = "";
214  iterator->activeCommandStartTime_ = time(0); // reset on any change
215 
216  if(theIteratorStruct.commandIndex_ <
217  theIteratorStruct.commandIterations_.size())
218  iterator->activeCommandIteration_ =
219  theIteratorStruct
220  .commandIterations_[theIteratorStruct.commandIndex_];
221  else
222  iterator->activeCommandIteration_ = -1;
223 
224  iterator->depthIterationStack_.clear();
225  for(const auto& depthIteration : theIteratorStruct.stepIndexStack_)
226  iterator->depthIterationStack_.push_back(depthIteration);
227  // if(theIteratorStruct.stepIndexStack_.size())
228  // iterator->activeLoopIteration_ =
229  // theIteratorStruct.stepIndexStack_.back(); else
230  // iterator->activeLoopIteration_ = -1;
231 
232  iterator->activeNumberOfCommands_ =
233  theIteratorStruct.commands_.size();
234  }
235 
236  } // end command handling and iterator mutex
237 
240  // do halt or pause action outside of iterator mutex
241 
242  if(theIteratorStruct.doPauseAction_)
243  {
244  // valid PAUSE-iterator command!
245 
246  // safely pause plan!
247  // i.e. check that command is complete
248 
249  __COUT__ << "Waiting to pause..." << __E__;
250  while(!iterator->checkCommand(&theIteratorStruct))
251  __COUT__ << "Waiting to pause..." << __E__;
252 
253  __COUT__ << "Completing pause..." << __E__;
254 
255  theIteratorStruct.doPauseAction_ = false; // clear
256 
257  // lockout the messages array for the remainder of the scope
258  // this guarantees the reading thread can safely access the messages
259  if(iterator->theSupervisor_->VERBOSE_MUTEX)
260  __COUT__ << "Waiting for iterator access" << __E__;
261  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
262  if(iterator->theSupervisor_->VERBOSE_MUTEX)
263  __COUT__ << "Have iterator access" << __E__;
264 
265  iterator->activePlanIsRunning_ = false;
266 
267  __COUT__ << "Paused plan '" << theIteratorStruct.activePlan_
268  << "' at command index " << theIteratorStruct.commandIndex_
269  << ". " << __E__;
270  __COUT__ << "Paused plan '" << theIteratorStruct.activePlan_
271  << "' at command index " << theIteratorStruct.commandIndex_
272  << ". " << __E__;
273 
274  continue; // resume workloop
275  }
276  else if(theIteratorStruct.doHaltAction_)
277  {
278  // valid HALT-iterator command!
279 
280  // safely end plan!
281  // i.e. check that command is complete
282 
283  __COUT__ << "Waiting to halt..." << __E__;
284  while(!iterator->checkCommand(&theIteratorStruct))
285  __COUT__ << "Waiting to halt..." << __E__;
286 
287  __COUT__ << "Completing halt..." << __E__;
288 
289  theIteratorStruct.doHaltAction_ = false; // clear
290 
291  iterator->haltIterator(iterator, &theIteratorStruct);
292 
293  // //last ditch effort to make sure FSM is halted
294  // iterator->haltIterator(
295  // iterator->theSupervisor_,
296  // theIteratorStruct.fsmName_);
297  //
298  // //lockout the messages array for the remainder of the scope
299  // //this guarantees the reading thread can safely access the
300  // messages
301  // if(iterator->theSupervisor_->VERBOSE_MUTEX) __COUT__ << "Waiting
302  // for iterator access" << __E__; std::lock_guard<std::mutex>
303  // lock(iterator->accessMutex_);
304  // if(iterator->theSupervisor_->VERBOSE_MUTEX) __COUT__ << "Have
305  // iterator access" << __E__;
306  //
307  // iterator->activePlanIsRunning_ = false;
308  // iterator->iteratorBusy_ = false;
309  //
310  // __COUT__ << "Halted plan '" << theIteratorStruct.activePlan_ << "'
311  // at command index " << theIteratorStruct.commandIndex_ <<
312  //". " << __E__;
313  // __COUT__ << "Halted plan '" << theIteratorStruct.activePlan_ << "'
314  // at command index " << theIteratorStruct.commandIndex_ <<
315  //". " << __E__;
316  //
317  // theIteratorStruct.activePlan_ = ""; //clear
318  // theIteratorStruct.commandIndex_ = -1; //clear
319 
320  continue; // resume workloop
321  }
322 
325  // handle running
326  // __COUT__ << "thinking.." << theIteratorStruct.running_ << " " <<
327  // theIteratorStruct.activePlan_ << " cmd=" <<
328  // theIteratorStruct.commandIndex_ << __E__;
329  if(theIteratorStruct.running_ &&
330  theIteratorStruct.activePlan_ !=
331  "") // important, because after errors, still "running" until halt
332  {
333  if(theIteratorStruct.commandIndex_ == (unsigned int)-1)
334  {
335  // initialize the running plan
336 
337  __COUT__ << "Get commands" << __E__;
338 
339  theIteratorStruct.commandIndex_ = 0;
340 
341  theIteratorStruct.cfgMgr_
342  ->init(); // completely reset to re-align with any changes
343 
344  if(theIteratorStruct.activePlan_ == Iterator::RESERVED_GEN_PLAN_NAME)
345  {
346  __COUT__ << "Using generated plan..." << __E__;
347  theIteratorStruct.onlyConfigIfNotConfigured_ =
348  iterator->genKeepConfiguration_;
349  theIteratorStruct.commands_ =
350  generateIterationPlan(iterator->genFsmName_,
351  iterator->genConfigAlias_,
352  iterator->genPlanDurationSeconds_,
353  iterator->genPlanNumberOfRuns_);
354  }
355  else
356  {
357  __COUT__ << "Getting iterator table..." << __E__;
358  itConfig =
359  theIteratorStruct.cfgMgr_->__GET_CONFIG__(IterateTable);
360  theIteratorStruct.onlyConfigIfNotConfigured_ = false;
361  theIteratorStruct.commands_ = itConfig->getPlanCommands(
362  theIteratorStruct.cfgMgr_, theIteratorStruct.activePlan_);
363  }
364 
365  // reset commandIteration counts
366  theIteratorStruct.commandIterations_.clear();
367  for(auto& command : theIteratorStruct.commands_)
368  {
369  theIteratorStruct.commandIterations_.push_back(0);
370  __COUT__ << "command " << command.type_ << __E__;
371  __COUT__ << "table "
372  << IterateTable::commandToTableMap_.at(command.type_)
373  << __E__;
374  __COUT__ << "param count = " << command.params_.size() << __E__;
375 
376  for(auto& param : command.params_)
377  {
378  __COUT__ << "\t param " << param.first << " : "
379  << param.second << __E__;
380  }
381  }
382 
383  theIteratorStruct.originalTrackChanges_ =
384  ConfigurationInterface::isVersionTrackingEnabled();
385  theIteratorStruct.originalConfigGroup_ =
386  theIteratorStruct.cfgMgr_->getActiveGroupName();
387  theIteratorStruct.originalConfigKey_ =
388  theIteratorStruct.cfgMgr_->getActiveGroupKey();
389 
390  __COUT__ << "originalTrackChanges "
391  << theIteratorStruct.originalTrackChanges_ << __E__;
392  __COUT__ << "originalConfigGroup "
393  << theIteratorStruct.originalConfigGroup_ << __E__;
394  __COUT__ << "originalConfigKey "
395  << theIteratorStruct.originalConfigKey_ << __E__;
396 
397  } // end initial section
398 
399  if(!theIteratorStruct.commandBusy_)
400  {
401  if(theIteratorStruct.commandIndex_ <
402  theIteratorStruct.commands_.size())
403  {
404  // execute command
405  theIteratorStruct.commandBusy_ = true;
406 
407  __COUT__ << "Iterator starting command "
408  << theIteratorStruct.commandIndex_ + 1 << ": "
409  << theIteratorStruct
410  .commands_[theIteratorStruct.commandIndex_]
411  .type_
412  << __E__;
413  __COUT__ << "Iterator starting command "
414  << theIteratorStruct.commandIndex_ + 1 << ": "
415  << theIteratorStruct
416  .commands_[theIteratorStruct.commandIndex_]
417  .type_
418  << __E__;
419 
420  iterator->startCommand(&theIteratorStruct);
421  }
422  else if(theIteratorStruct.commandIndex_ ==
423  theIteratorStruct.commands_.size()) // Done!
424  {
425  __COUT__ << "Finished Iteration Plan '"
426  << theIteratorStruct.activePlan_ << __E__;
427  __COUT__ << "Finished Iteration Plan '"
428  << theIteratorStruct.activePlan_ << __E__;
429 
430  __COUT__ << "Reverting track changes." << __E__;
431  ConfigurationInterface::setVersionTrackingEnabled(
432  theIteratorStruct.originalTrackChanges_);
433 
434  //l
435  __COUT__ << "Activating original group..." << __E__;
436  try
437  {
438  theIteratorStruct.cfgMgr_->activateTableGroup(
439  theIteratorStruct.originalConfigGroup_,
440  theIteratorStruct.originalConfigKey_);
441  }
442  catch(...)
443  {
444  __COUT_WARN__ << "Original group could not be activated."
445  << __E__;
446  }
447 
448  // leave FSM halted
449  __COUT__ << "Completing Iteration Plan and cleaning up..."
450  << __E__;
451 
452  iterator->haltIterator(
453  iterator, &theIteratorStruct, true /* doNotHaltFSM */);
454  }
455  }
456  else if(theIteratorStruct.commandBusy_)
457  {
458  // check for command completion
459  if(iterator->checkCommand(&theIteratorStruct))
460  {
461  theIteratorStruct.commandBusy_ = false; // command complete
462 
463  ++theIteratorStruct.commandIndex_;
464 
465  __COUT__ << "Ready for next command. Done with "
466  << theIteratorStruct.commandIndex_ << " of "
467  << theIteratorStruct.commands_.size() << __E__;
468  __COUT__ << "Iterator ready for next command. Done with "
469  << theIteratorStruct.commandIndex_ << " of "
470  << theIteratorStruct.commands_.size() << __E__;
471  }
472 
473  // Note: check command gets one shot to resume
474  if(theIteratorStruct.doResumeAction_) // end resume action
475  theIteratorStruct.doResumeAction_ = false;
476  }
477 
478  } // end running
479  else
480  sleep(1); // when inactive sleep a lot
481 
484 
485  // __COUT__ << "end loop.." << theIteratorStruct.running_ << " " <<
486  // theIteratorStruct.activePlan_ << " cmd=" <<
487  // theIteratorStruct.commandIndex_ << __E__;
488  } /* code */
489  } //end try/catch
490  catch(const std::runtime_error& e) //insert info about the state of the iterator
491  {
492  if(theIteratorStruct.activePlan_ != "")
493  {
494  __SS__ << "The active Iterator plan name is '"
495  << theIteratorStruct.activePlan_
496  << "'... Here was the error: " << e.what() << __E__;
497  __SS_THROW__;
498  }
499  else
500  throw;
501  }
502 
503  iterator->workloopRunning_ = false; // if we ever exit
504 } //end IteratorWorkLoop()
505 catch(const std::runtime_error& e)
506 {
507  __SS__ << "Encountered error in Iterator thread. Here is the error:\n"
508  << e.what() << __E__;
509  __COUT_ERR__ << ss.str();
510 
511  // lockout the messages array for the remainder of the scope
512  // this guarantees the reading thread can safely access the messages
513  if(iterator->theSupervisor_->VERBOSE_MUTEX)
514  __COUT__ << "Waiting for iterator access" << __E__;
515  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
516  if(iterator->theSupervisor_->VERBOSE_MUTEX)
517  __COUT__ << "Have iterator access" << __E__;
518 
519  iterator->workloopRunning_ = false; // if we ever exit
520  iterator->errorMessage_ = ss.str();
521 }
522 catch(...)
523 {
524  __SS__ << "Encountered unknown error in Iterator thread." << __E__;
525  try
526  {
527  throw;
528  } //one more try to printout extra info
529  catch(const std::exception& e)
530  {
531  ss << "Exception message: " << e.what();
532  }
533  catch(...)
534  {
535  }
536  __COUT_ERR__ << ss.str();
537 
538  // lockout the messages array for the remainder of the scope
539  // this guarantees the reading thread can safely access the messages
540  if(iterator->theSupervisor_->VERBOSE_MUTEX)
541  __COUT__ << "Waiting for iterator access" << __E__;
542  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
543  if(iterator->theSupervisor_->VERBOSE_MUTEX)
544  __COUT__ << "Have iterator access" << __E__;
545 
546  iterator->workloopRunning_ = false; // if we ever exit
547  iterator->errorMessage_ = ss.str();
548 } // end IteratorWorkLoop() exception handling
549 
550 //==============================================================================
551 void Iterator::startCommand(IteratorWorkLoopStruct* iteratorStruct)
552 try
553 {
554  {
555  int i = 0;
556  for(const auto& depthIteration : iteratorStruct->stepIndexStack_)
557  {
558  __COUT__ << i++ << ":" << depthIteration << __E__;
559  }
560  }
561 
562  // should be mutually exclusive with GatewaySupervisor main thread state machine
563  // accesses lockout the messages array for the remainder of the scope this
564  // guarantees the reading thread can safely access the messages
565  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
566  __COUT__ << "Waiting for FSM access" << __E__;
567  std::lock_guard<std::mutex> lock(
568  iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_);
569  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
570  __COUT__ << "Have FSM access" << __E__;
571 
572  // for out of range, throw exception - should never happen
573  if(iteratorStruct->commandIndex_ >= iteratorStruct->commands_.size())
574  {
575  __SS__ << "Out of range commandIndex = " << iteratorStruct->commandIndex_
576  << " in size = " << iteratorStruct->commands_.size() << __E__;
577  __SS_THROW__;
578  }
579 
580  // increment iteration count for command
581  ++iteratorStruct->commandIterations_[iteratorStruct->commandIndex_];
582 
583  std::string type = iteratorStruct->commands_[iteratorStruct->commandIndex_].type_;
585  {
586  return startCommandBeginLabel(iteratorStruct);
587  }
588  else if(type == IterateTable::COMMAND_CHOOSE_FSM)
589  {
590  return startCommandChooseFSM(
591  iteratorStruct,
592  iteratorStruct->commands_[iteratorStruct->commandIndex_]
593  .params_[IterateTable::commandChooseFSMParams_.NameOfFSM_]);
594  }
595  else if(type == IterateTable::COMMAND_CONFIGURE_ACTIVE_GROUP)
596  {
597  return startCommandConfigureActive(iteratorStruct);
598  }
599  else if(type == IterateTable::COMMAND_CONFIGURE_ALIAS)
600  {
601  return startCommandConfigureAlias(
602  iteratorStruct,
603  iteratorStruct->commands_[iteratorStruct->commandIndex_]
604  .params_[IterateTable::commandConfigureAliasParams_.SystemAlias_]);
605  }
606  else if(type == IterateTable::COMMAND_CONFIGURE_GROUP)
607  {
608  return startCommandConfigureGroup(iteratorStruct);
609  }
610  else if(type == IterateTable::COMMAND_ACTIVATE_ALIAS)
611  {
612  ConfigurationManagerRW* cfgMgr = iteratorStruct->cfgMgr_;
613  std::pair<std::string, TableGroupKey> newActiveGroup =
614  cfgMgr->getTableGroupFromAlias(
615  iteratorStruct->commands_[iteratorStruct->commandIndex_]
616  .params_[IterateTable::commandActivateAliasParams_.SystemAlias_]);
617  cfgMgr->loadTableGroup(
618  newActiveGroup.first, newActiveGroup.second, true /*activate*/);
619  }
620  else if(type == IterateTable::COMMAND_ACTIVATE_GROUP)
621  {
622  ConfigurationManagerRW* cfgMgr = iteratorStruct->cfgMgr_;
623  cfgMgr->loadTableGroup(
624  iteratorStruct->commands_[iteratorStruct->commandIndex_]
625  .params_[IterateTable::commandActivateGroupParams_.GroupName_],
627  iteratorStruct->commands_[iteratorStruct->commandIndex_]
628  .params_[IterateTable::commandActivateGroupParams_.GroupKey_]),
629  true /*activate*/);
630  }
631  else if(type == IterateTable::COMMAND_EXECUTE_FE_MACRO)
632  {
633  return startCommandMacro(iteratorStruct, true /*isFEMacro*/);
634  }
635  else if(type == IterateTable::COMMAND_EXECUTE_MACRO)
636  {
637  return startCommandMacro(iteratorStruct, false /*isFEMacro*/);
638  }
639  else if(type == IterateTable::COMMAND_MODIFY_ACTIVE_GROUP)
640  {
641  return startCommandModifyActive(iteratorStruct);
642  }
643  else if(type == IterateTable::COMMAND_REPEAT_LABEL)
644  {
645  return startCommandRepeatLabel(iteratorStruct);
646  }
647  else if(type == IterateTable::COMMAND_RUN)
648  {
649  return startCommandRun(iteratorStruct);
650  }
651  else if(type == IterateTable::COMMAND_START)
652  {
653  return startCommandFSMTransition(iteratorStruct,
654  RunControlStateMachine::START_TRANSITION_NAME);
655  }
656  else if(type == IterateTable::COMMAND_STOP)
657  {
658  return startCommandFSMTransition(iteratorStruct,
659  RunControlStateMachine::STOP_TRANSITION_NAME);
660  }
661  else if(type == IterateTable::COMMAND_PAUSE)
662  {
663  return startCommandFSMTransition(iteratorStruct,
664  RunControlStateMachine::PAUSE_TRANSITION_NAME);
665  }
666  else if(type == IterateTable::COMMAND_RESUME)
667  {
668  return startCommandFSMTransition(iteratorStruct,
669  RunControlStateMachine::RESUME_TRANSITION_NAME);
670  }
671  else if(type == IterateTable::COMMAND_HALT)
672  {
673  return startCommandFSMTransition(iteratorStruct,
674  RunControlStateMachine::HALT_TRANSITION_NAME);
675  }
676  else
677  {
678  __SS__ << "Failed attempt to start unrecognized command type = " << type << __E__;
679  __COUT_ERR__ << ss.str();
680  __SS_THROW__;
681  }
682 }
683 catch(...)
684 {
685  __COUT__ << "Error caught. Reverting track changes." << __E__;
686  ConfigurationInterface::setVersionTrackingEnabled(
687  iteratorStruct->originalTrackChanges_);
688 
689  __COUT__ << "Activating original group..." << __E__;
690  try
691  {
692  iteratorStruct->cfgMgr_->activateTableGroup(iteratorStruct->originalConfigGroup_,
693  iteratorStruct->originalConfigKey_);
694  }
695  catch(...)
696  {
697  __COUT_WARN__ << "Original group could not be activated." << __E__;
698  }
699  throw;
700 } // end startCommand()
701 
702 //==============================================================================
706 bool Iterator::checkCommand(IteratorWorkLoopStruct* iteratorStruct)
707 try
708 {
709  // for out of range, return done
710  if(iteratorStruct->commandIndex_ >= iteratorStruct->commands_.size())
711  {
712  __COUT__ << "Out of range commandIndex = " << iteratorStruct->commandIndex_
713  << " in size = " << iteratorStruct->commands_.size() << __E__;
714  return true;
715  }
716 
717  std::string type = iteratorStruct->commands_[iteratorStruct->commandIndex_].type_;
719  {
720  // do nothing
721  return true;
722  }
723  else if(type == IterateTable::COMMAND_CHOOSE_FSM)
724  {
725  // do nothing
726  return true;
727  }
728  else if(type == IterateTable::COMMAND_CONFIGURE_ALIAS ||
729  type == IterateTable::COMMAND_CONFIGURE_ACTIVE_GROUP ||
730  type == IterateTable::COMMAND_CONFIGURE_GROUP)
731  {
732  return checkCommandConfigure(iteratorStruct);
733  }
734  else if(type == IterateTable::COMMAND_ACTIVATE_ALIAS ||
735  type == IterateTable::COMMAND_ACTIVATE_GROUP)
736  {
737  // do nothing
738  return true;
739  }
740  else if(type == IterateTable::COMMAND_EXECUTE_FE_MACRO)
741  {
742  return checkCommandMacro(iteratorStruct, true /*isFEMacro*/);
743  }
744  else if(type == IterateTable::COMMAND_EXECUTE_MACRO)
745  {
746  return checkCommandMacro(iteratorStruct, false /*isFEMacro*/);
747  }
748  else if(type == IterateTable::COMMAND_MODIFY_ACTIVE_GROUP)
749  {
750  // do nothing
751  return true;
752  }
753  else if(type == IterateTable::COMMAND_REPEAT_LABEL)
754  {
755  // do nothing
756  return true;
757  }
758  else if(type == IterateTable::COMMAND_RUN)
759  {
760  return checkCommandRun(iteratorStruct);
761  }
762  else if(type == IterateTable::COMMAND_START)
763  {
764  return checkCommandFSMTransition(iteratorStruct, "Running");
765  }
766  else if(type == IterateTable::COMMAND_STOP)
767  {
768  return checkCommandFSMTransition(iteratorStruct, "Configured");
769  }
770  else if(type == IterateTable::COMMAND_PAUSE)
771  {
772  return checkCommandFSMTransition(iteratorStruct, "Paused");
773  }
774  else if(type == IterateTable::COMMAND_RESUME)
775  {
776  return checkCommandFSMTransition(iteratorStruct, "Running");
777  }
778  else if(type == IterateTable::COMMAND_HALT)
779  {
780  return checkCommandFSMTransition(iteratorStruct,
781  RunControlStateMachine::HALTED_STATE_NAME);
782  }
783  else
784  {
785  __SS__ << "Attempt to check unrecognized command type = " << type << __E__;
786  __COUT_ERR__ << ss.str();
787  __SS_THROW__;
788  }
789 }
790 catch(...)
791 {
792  __COUT__ << "Error caught. Reverting track changes." << __E__;
793  ConfigurationInterface::setVersionTrackingEnabled(
794  iteratorStruct->originalTrackChanges_);
795 
796  __COUT__ << "Activating original group..." << __E__;
797  try
798  {
799  iteratorStruct->cfgMgr_->activateTableGroup(iteratorStruct->originalConfigGroup_,
800  iteratorStruct->originalConfigKey_);
801  }
802  catch(...)
803  {
804  __COUT_WARN__ << "Original group could not be activated." << __E__;
805  }
806 
807  throw;
808 } // end checkCommand()
809 
810 //==============================================================================
811 void Iterator::startCommandChooseFSM(IteratorWorkLoopStruct* iteratorStruct,
812  const std::string& fsmName)
813 {
814  __COUT__ << "fsmName " << fsmName << __E__;
815 
816  iteratorStruct->fsmName_ = fsmName;
817  iteratorStruct->theIterator_->lastFsmName_ = fsmName;
818 
819  // Translate fsmName
820  // to gives us run alias (fsmRunAlias_) and next run number (fsmNextRunNumber_)
821 
822  // CAREFUL?? Threads
823 
825 
826  iteratorStruct->fsmRunAlias_ = "Run"; // default to "Run"
827 
828  // get stateMachineAliasFilter if possible
829  ConfigurationTree configLinkNode = iteratorStruct->cfgMgr_->getSupervisorTableNode(
830  iteratorStruct->theIterator_->theSupervisor_->getContextUID(),
831  iteratorStruct->theIterator_->theSupervisor_->getSupervisorUID());
832 
833  if(!configLinkNode.isDisconnected())
834  {
835  try // for backwards compatibility
836  {
837  ConfigurationTree fsmLinkNode =
838  configLinkNode.getNode("LinkToStateMachineTable");
839  if(!fsmLinkNode.isDisconnected())
840  iteratorStruct->fsmRunAlias_ =
841  fsmLinkNode.getNode(fsmName + "/RunDisplayAlias")
842  .getValue<std::string>();
843  else
844  __COUT_INFO__ << "FSM Link disconnected." << __E__;
845  }
846  catch(std::runtime_error& e)
847  {
848  //__COUT_INFO__ << e.what() << __E__;
849  __COUT_INFO__
850  << "No state machine Run alias. Ignoring and assuming alias of '"
851  << iteratorStruct->fsmRunAlias_ << ".'" << __E__;
852  }
853  catch(...)
854  {
855  __COUT_ERR__ << "Unknown error. Should never happen." << __E__;
856 
857  __COUT_INFO__
858  << "No state machine Run alias. Ignoring and assuming alias of '"
859  << iteratorStruct->fsmRunAlias_ << ".'" << __E__;
860  }
861  }
862  else
863  __COUT_INFO__ << "FSM Link disconnected." << __E__;
864 
865  __COUT__ << "fsmRunAlias_ = " << iteratorStruct->fsmRunAlias_ << __E__;
866 
868 
869  iteratorStruct->fsmNextRunNumber_ =
870  iteratorStruct->theIterator_->theSupervisor_->getNextRunNumber(
871  iteratorStruct->fsmName_);
872 
873  if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_
874  .getCurrentStateName() == "Running" ||
875  iteratorStruct->theIterator_->theSupervisor_->theStateMachine_
876  .getCurrentStateName() == "Paused")
877  --iteratorStruct->fsmNextRunNumber_; // current run number is one back
878 
879  __COUT__ << "fsmNextRunNumber_ = " << iteratorStruct->fsmNextRunNumber_ << __E__;
880 } // end startCommandChooseFSM()
881 
882 //==============================================================================
884 bool Iterator::haltIterator(Iterator* iterator,
885  IteratorWorkLoopStruct* iteratorStruct /* = 0 */,
886  bool doNotHaltFSM /* = false */)
887 
888 {
889  GatewaySupervisor* theSupervisor = iterator->theSupervisor_;
890  const std::string& fsmName = iterator->lastFsmName_;
891 
892  std::vector<std::string> fsmCommandParameters;
893  std::string errorStr = "";
894  std::string currentState = theSupervisor->theStateMachine_.getCurrentStateName();
895 
896  __COUTV__(currentState);
897 
898  bool haltAttempted = true;
899  if(doNotHaltFSM)
900  {
901  __COUT_INFO__ << "Iterator is leaving FSM in current state: " << currentState
902  << ". If this is undesireable, add a Halt command, for example, to "
903  "the end of your Iteration plan."
904  << __E__;
905  haltAttempted = false;
906  }
907  else if(currentState == RunControlStateMachine::INITIAL_STATE_NAME ||
908  currentState == RunControlStateMachine::HALTED_STATE_NAME)
909  {
910  __COUT__ << "Do nothing. Already halted." << __E__;
911  haltAttempted = false;
912  }
913  else if(currentState == "Running")
914  errorStr = theSupervisor->attemptStateMachineTransition(
915  0,
916  0,
917  RunControlStateMachine::ABORT_TRANSITION_NAME,
918  fsmName,
919  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
920  WebUsers::DEFAULT_ITERATOR_USERNAME,
921  fsmCommandParameters);
922  else
923  errorStr = theSupervisor->attemptStateMachineTransition(
924  0,
925  0,
926  RunControlStateMachine::HALT_TRANSITION_NAME,
927  fsmName,
928  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
929  WebUsers::DEFAULT_ITERATOR_USERNAME,
930  fsmCommandParameters);
931 
932  if(haltAttempted)
933  {
934  if(errorStr != "")
935  {
936  __SS__ << "Iterator failed to halt because of the following error: "
937  << errorStr;
938  __SS_THROW__;
939  }
940 
941  // else successfully launched
942  __COUT__ << "FSM in transition = "
943  << theSupervisor->theStateMachine_.isInTransition() << __E__;
944  __COUT__ << "halting state machine launched." << __E__;
945  }
946 
947  // finish up cleanup of the iterator
948  __COUT__ << "Conducting Iterator cleanup." << __E__;
949 
950  if(iteratorStruct)
951  {
952  __COUT__ << "Reverting track changes." << __E__;
953  ConfigurationInterface::setVersionTrackingEnabled(
954  iteratorStruct->originalTrackChanges_);
955 
956  if(!doNotHaltFSM)
957  {
958  __COUT__ << "Activating original group..." << __E__;
959  try
960  {
961  iteratorStruct->cfgMgr_->activateTableGroup(
962  iteratorStruct->originalConfigGroup_,
963  iteratorStruct->originalConfigKey_);
964  }
965  catch(...)
966  {
967  __COUT_WARN__ << "Original group could not be activated." << __E__;
968  }
969  }
970  }
971 
972  // lockout the messages array for the remainder of the scope
973  // this guarantees the reading thread can safely access the messages
974  if(iterator->theSupervisor_->VERBOSE_MUTEX)
975  __COUT__ << "Waiting for iterator access" << __E__;
976  std::lock_guard<std::mutex> lock(iterator->accessMutex_);
977  if(iterator->theSupervisor_->VERBOSE_MUTEX)
978  __COUT__ << "Have iterator access" << __E__;
979 
980  iterator->activePlanIsRunning_ = false;
981  iterator->iteratorBusy_ = false;
982 
983  // clear
984  iterator->activePlanName_ = "";
985  iterator->activeCommandIndex_ = -1;
986 
987  if(iteratorStruct)
988  {
989  __COUT__ << "Iterator cleanup complete of plan '" << iteratorStruct->activePlan_
990  << "' at command index " << iteratorStruct->commandIndex_ << ". "
991  << __E__;
992 
993  iterator->lastFinishedPlanName_ = iteratorStruct->activePlan_;
994  FILE* fp = fopen((ITERATOR_PLAN_HISTORY_FILENAME).c_str(), "w");
995  if(fp)
996  {
997  fprintf(fp, "%s\n", iterator->lastStartedPlanName_.c_str());
998  fprintf(fp, "%s\n", iterator->lastFinishedPlanName_.c_str());
999  fclose(fp);
1000  }
1001  else
1002  __COUT_WARN__ << "Could not open Iterator history file: "
1003  << ITERATOR_PLAN_HISTORY_FILENAME << __E__;
1004 
1005  iteratorStruct->activePlan_ = ""; // clear
1006  iteratorStruct->commandIndex_ = -1; // clear
1007  }
1008 
1009  return haltAttempted;
1010 } // end haltIterator()
1011 
1012 //==============================================================================
1013 void Iterator::startCommandBeginLabel(IteratorWorkLoopStruct* iteratorStruct)
1014 {
1015  __COUT__ << "Entering label '"
1016  << iteratorStruct->commands_[iteratorStruct->commandIndex_]
1017  .params_[IterateTable::commandBeginLabelParams_.Label_]
1018  << "'..." << std::endl;
1019 
1020  // add new step index to stack
1021  iteratorStruct->stepIndexStack_.push_back(0);
1022 } // end startCommandBeginLabel()
1023 
1024 //==============================================================================
1025 void Iterator::startCommandRepeatLabel(IteratorWorkLoopStruct* iteratorStruct)
1026 {
1027  // search for first matching label backward and set command to there
1028 
1029  int numOfRepetitions;
1030  sscanf(iteratorStruct->commands_[iteratorStruct->commandIndex_]
1031  .params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_]
1032  .c_str(),
1033  "%d",
1034  &numOfRepetitions);
1035  __COUT__ << "numOfRepetitions remaining = " << numOfRepetitions << __E__;
1036 
1037  char repStr[200];
1038 
1039  if(numOfRepetitions <= 0)
1040  {
1041  // write original number of repetitions value back
1042  sprintf(repStr, "%d", iteratorStruct->stepIndexStack_.back());
1043  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1044  .params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_] =
1045  repStr; // re-store as string
1046 
1047  // remove step index from stack
1048  iteratorStruct->stepIndexStack_.pop_back();
1049 
1050  return; // no more repetitions
1051  }
1052 
1053  --numOfRepetitions;
1054 
1055  // increment step index in stack
1056  ++(iteratorStruct->stepIndexStack_.back());
1057 
1058  unsigned int i;
1059  for(i = iteratorStruct->commandIndex_; i > 0;
1060  --i) // assume 0 is always the fallback option
1061  if(iteratorStruct->commands_[i].type_ == IterateTable::COMMAND_BEGIN_LABEL &&
1062  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1063  .params_[IterateTable::commandRepeatLabelParams_.Label_] ==
1064  iteratorStruct->commands_[i]
1065  .params_[IterateTable::commandBeginLabelParams_.Label_])
1066  break;
1067 
1068  sprintf(repStr, "%d", numOfRepetitions);
1069  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1070  .params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_] =
1071  repStr; // re-store as string
1072 
1073  iteratorStruct->commandIndex_ = i;
1074  __COUT__ << "Jumping back to commandIndex " << iteratorStruct->commandIndex_ << __E__;
1075 } // end startCommandRepeatLabel()
1076 
1077 //==============================================================================
1078 void Iterator::startCommandRun(IteratorWorkLoopStruct* iteratorStruct)
1079 {
1080  __COUT__ << "startCommandRun " << __E__;
1081 
1082  iteratorStruct->runIsDone_ = false;
1083  iteratorStruct->fsmCommandParameters_.clear();
1084 
1085  std::string errorStr = "";
1086  std::string currentState = iteratorStruct->theIterator_->theSupervisor_
1087  ->theStateMachine_.getCurrentStateName();
1088 
1089  // execute first transition (may need two)
1090 
1091  __COUTTV__(iteratorStruct->theIterator_->genLogEntry_);
1092 
1093  if(currentState == RunControlStateMachine::CONFIGURED_STATE_NAME)
1094  errorStr =
1095  iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(
1096  0,
1097  0,
1098  RunControlStateMachine::START_TRANSITION_NAME,
1099  iteratorStruct->fsmName_,
1100  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1101  WebUsers::DEFAULT_ITERATOR_USERNAME,
1102  iteratorStruct->fsmCommandParameters_,
1103  iteratorStruct->activePlan_ == Iterator::RESERVED_GEN_PLAN_NAME
1104  ? iteratorStruct->theIterator_->genLogEntry_
1105  : "");
1106  else
1107  errorStr = "Can only Run from the Configured state. The current state is " +
1108  currentState;
1109 
1110  if(errorStr != "")
1111  {
1112  __SS__ << "Iterator failed to run because of the following error: " << errorStr;
1113  __SS_THROW__;
1114  }
1115 
1116  // save original duration
1117  sscanf(iteratorStruct->commands_[iteratorStruct->commandIndex_]
1118  .params_[IterateTable::commandRunParams_.DurationInSeconds_]
1119  .c_str(),
1120  "%ld",
1121  &iteratorStruct->originalDurationInSeconds_);
1122  __COUTV__(iteratorStruct->originalDurationInSeconds_);
1123 
1124  // else successfully launched
1125  __COUT__
1126  << "FSM in transition = "
1127  << iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition()
1128  << __E__;
1129  __COUT__ << "startCommandRun success." << __E__;
1130 } // end startCommandRun()
1131 
1132 //==============================================================================
1133 void Iterator::startCommandConfigureActive(IteratorWorkLoopStruct* iteratorStruct)
1134 {
1135  __COUT__ << "startCommandConfigureActive " << __E__;
1136 
1137  // steps:
1138  // get active config group
1139  // transition to configure with parameters describing group
1140 
1141  std::string group = iteratorStruct->cfgMgr_->getActiveGroupName();
1142  TableGroupKey key = iteratorStruct->cfgMgr_->getActiveGroupKey();
1143 
1144  __COUT__ << "group " << group << __E__;
1145  __COUT__ << "key " << key << __E__;
1146 
1147  // create special alias for this group using : separators
1148 
1149  std::stringstream systemAlias;
1150  systemAlias << "GROUP:" << group << ":" << key;
1151  startCommandConfigureAlias(iteratorStruct, systemAlias.str());
1152 } // end startCommandConfigureActive()
1153 
1154 //==============================================================================
1155 void Iterator::startCommandConfigureGroup(IteratorWorkLoopStruct* iteratorStruct)
1156 {
1157  __COUT__ << "startCommandConfigureGroup " << __E__;
1158 
1159  // steps:
1160  // transition to configure with parameters describing group
1161 
1162  std::string group =
1163  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1164  .params_[IterateTable::commandConfigureGroupParams_.GroupName_];
1165  TableGroupKey key =
1166  TableGroupKey(iteratorStruct->commands_[iteratorStruct->commandIndex_]
1167  .params_[IterateTable::commandConfigureGroupParams_.GroupKey_]);
1168 
1169  __COUT__ << "group " << group << __E__;
1170  __COUT__ << "key " << key << __E__;
1171 
1172  // create special alias for this group using : separators
1173 
1174  std::stringstream systemAlias;
1175  systemAlias << "GROUP:" << group << ":" << key;
1176  startCommandConfigureAlias(iteratorStruct, systemAlias.str());
1177 } // end startCommandConfigureGroup()
1178 
1179 //==============================================================================
1180 void Iterator::startCommandConfigureAlias(IteratorWorkLoopStruct* iteratorStruct,
1181  const std::string& systemAlias)
1182 {
1183  __COUT__ << "systemAlias " << systemAlias << __E__;
1184 
1185  iteratorStruct->fsmCommandParameters_.clear();
1186  iteratorStruct->fsmCommandParameters_.push_back(systemAlias);
1187 
1188  std::string errorStr = "";
1189  std::string currentState = iteratorStruct->theIterator_->theSupervisor_
1190  ->theStateMachine_.getCurrentStateName();
1191 
1192  // execute first transition (may need two in conjunction with checkCommandConfigure())
1193 
1194  if(currentState == RunControlStateMachine::INITIAL_STATE_NAME)
1195  errorStr =
1196  iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(
1197  0,
1198  0,
1199  RunControlStateMachine::INIT_TRANSITION_NAME,
1200  iteratorStruct->fsmName_,
1201  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1202  WebUsers::DEFAULT_ITERATOR_USERNAME,
1203  iteratorStruct->fsmCommandParameters_);
1204  else if(currentState == RunControlStateMachine::HALTED_STATE_NAME)
1205  errorStr =
1206  iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(
1207  0,
1208  0,
1209  RunControlStateMachine::CONFIGURE_TRANSITION_NAME,
1210  iteratorStruct->fsmName_,
1211  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1212  WebUsers::DEFAULT_ITERATOR_USERNAME,
1213  iteratorStruct->fsmCommandParameters_);
1214  else if(currentState == RunControlStateMachine::CONFIGURED_STATE_NAME ||
1215  currentState == RunControlStateMachine::FAILED_STATE_NAME)
1216  {
1217  if(iteratorStruct->onlyConfigIfNotConfigured_ &&
1218  currentState != RunControlStateMachine::FAILED_STATE_NAME)
1219  __COUT__ << "Already configured, so do nothing!" << __E__;
1220  else
1221  errorStr = iteratorStruct->theIterator_->theSupervisor_
1222  ->attemptStateMachineTransition(
1223  0,
1224  0,
1225  RunControlStateMachine::HALT_TRANSITION_NAME,
1226  iteratorStruct->fsmName_,
1227  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1228  WebUsers::DEFAULT_ITERATOR_USERNAME,
1229  iteratorStruct->fsmCommandParameters_);
1230  }
1231  else
1232  errorStr =
1233  "Can only Configure from the Initial or Halted state. The current state is " +
1234  currentState;
1235 
1236  if(errorStr != "")
1237  {
1238  __SS__ << "Iterator failed to configure with system alias '"
1239  << (iteratorStruct->fsmCommandParameters_.size()
1240  ? iteratorStruct->fsmCommandParameters_[0]
1241  : "UNKNOWN")
1242  << "' because of the following error: " << errorStr;
1243  __SS_THROW__;
1244  }
1245 
1246  // else successfully launched
1247  __COUT__
1248  << "FSM in transition = "
1249  << iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition()
1250  << __E__;
1251  __COUT__ << "startCommandConfigureAlias success." << __E__;
1252 } // end startCommandConfigureAlias()
1253 
1254 //==============================================================================
1255 void Iterator::startCommandFSMTransition(IteratorWorkLoopStruct* iteratorStruct,
1256  const std::string& transitionCommand)
1257 {
1258  __COUTV__(transitionCommand);
1259 
1260  iteratorStruct->fsmCommandParameters_.clear();
1261 
1262  std::string errorStr = "";
1263  std::string currentState = iteratorStruct->theIterator_->theSupervisor_
1264  ->theStateMachine_.getCurrentStateName();
1265 
1266  // execute first transition (may need two in conjunction with checkCommandConfigure())
1267 
1268  __COUTV__(currentState);
1269 
1270  errorStr =
1271  iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(
1272  0,
1273  0,
1274  transitionCommand,
1275  iteratorStruct->fsmName_,
1276  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1277  WebUsers::DEFAULT_ITERATOR_USERNAME,
1278  iteratorStruct->fsmCommandParameters_,
1279  (transitionCommand == RunControlStateMachine::START_TRANSITION_NAME &&
1280  iteratorStruct->activePlan_ == Iterator::RESERVED_GEN_PLAN_NAME)
1281  ? iteratorStruct->theIterator_->genLogEntry_
1282  : "");
1283 
1284  if(errorStr != "")
1285  {
1286  __SS__ << "Iterator failed to " << transitionCommand << " with ";
1287  if(iteratorStruct->fsmCommandParameters_.size() == 0)
1288  ss << "no parameters ";
1289  else
1290  ss << "parameters '"
1291  << StringMacros::vectorToString(iteratorStruct->fsmCommandParameters_)
1292  << "' ";
1293  ss << "' because of the following error: " << errorStr;
1294  __SS_THROW__;
1295  }
1296 
1297  // else successfully launched
1298  __COUT__
1299  << "FSM in transition = "
1300  << iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition()
1301  << __E__;
1302  __COUT__ << "startCommandFSMTransition success." << __E__;
1303 } // end startCommandFSMTransition()
1304 
1305 //==============================================================================
1306 void Iterator::startCommandMacro(IteratorWorkLoopStruct* iteratorStruct,
1307  bool isFrontEndMacro)
1308 {
1309  // Steps:
1310  // 4 parameters CommandExecuteFEMacroParams:
1311  // //targets
1312  // const std::string FEMacroName_ = "FEMacroName";
1313  // //macro parameters (table/groupID)
1314 
1315  const std::string& macroName =
1316  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1317  .params_[IterateTable::commandExecuteMacroParams_.MacroName_];
1318  const std::string& enableSavingOutput =
1319  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1320  .params_[IterateTable::commandExecuteMacroParams_.EnableSavingOutput_];
1321  const std::string& outputFilePath =
1322  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1323  .params_[IterateTable::commandExecuteMacroParams_.OutputFilePath_];
1324  const std::string& outputFileRadix =
1325  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1326  .params_[IterateTable::commandExecuteMacroParams_.OutputFileRadix_];
1327  const std::string& inputArgs =
1328  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1329  .params_[IterateTable::commandExecuteMacroParams_.MacroArgumentString_];
1330 
1331  __COUTV__(macroName);
1332  __COUTV__(enableSavingOutput);
1333  __COUTV__(outputFilePath);
1334  __COUTV__(outputFileRadix);
1335  __COUTV__(inputArgs);
1336 
1337  // send request to MacroMaker a la FEVInterface::runFrontEndMacro
1338  // but need to pass iteration information, so that the call is launched by just one
1339  // send to each front end. Front-ends must immediately respond that is started
1340  // FEVInterfacesManager.. must start a thread for running the macro iterations
1341  // Then check for complete.
1342 
1343  iteratorStruct->targetsDone_.clear(); // reset
1344 
1345  __COUTV__(iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.size());
1346  for(const auto& target :
1347  iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_)
1348  {
1349  __COUT__ << "target " << target.table_ << ":" << target.UID_ << __E__;
1350 
1351  // for each target, init to not done
1352  iteratorStruct->targetsDone_.push_back(false);
1353 
1354  xoap::MessageReference message =
1355  SOAPUtilities::makeSOAPMessageReference("FECommunication");
1356 
1357  SOAPParameters parameters;
1358  std::string type = isFrontEndMacro ? "feMacroMultiDimensionalStart"
1359  : "macroMultiDimensionalStart";
1360  parameters.addParameter("type", type);
1361  parameters.addParameter("requester", WebUsers::DEFAULT_ITERATOR_USERNAME);
1362  parameters.addParameter("targetInterfaceID", target.UID_);
1363  parameters.addParameter(isFrontEndMacro ? "feMacroName" : "macroName", macroName);
1364  parameters.addParameter("enableSavingOutput", enableSavingOutput);
1365  parameters.addParameter("outputFilePath", outputFilePath);
1366  parameters.addParameter("outputFileRadix", outputFileRadix);
1367  parameters.addParameter("inputArgs", inputArgs);
1368  SOAPUtilities::addParameters(message, parameters);
1369 
1370  __COUT__ << "Sending FE communication: " << SOAPUtilities::translate(message)
1371  << __E__;
1372 
1373  xoap::MessageReference replyMessage =
1374  iteratorStruct->theIterator_->theSupervisor_
1375  ->SOAPMessenger::sendWithSOAPReply(
1376  iteratorStruct->theIterator_->theSupervisor_->allSupervisorInfo_
1377  .getAllMacroMakerTypeSupervisorInfo()
1378  .begin()
1379  ->second.getDescriptor(),
1380  message);
1381 
1382  __COUT__ << "Response received: " << SOAPUtilities::translate(replyMessage)
1383  << __E__;
1384 
1385  SOAPParameters rxParameters;
1386  rxParameters.addParameter("Error");
1387  std::string response = SOAPUtilities::receive(replyMessage, rxParameters);
1388 
1389  std::string error = rxParameters.getValue("Error");
1390 
1391  if(response != type + "Done" || error != "")
1392  {
1393  // error occurred!
1394  __SS__ << "Error transmitting request to target interface '" << target.UID_
1395  << "' from '" << WebUsers::DEFAULT_ITERATOR_USERNAME << ".' Response '"
1396  << response << "' with error: " << error << __E__;
1397  __SS_THROW__;
1398  }
1399  } // end target loop
1400 
1401 } // end startCommandMacro()
1402 
1403 //==============================================================================
1404 bool Iterator::checkCommandMacro(IteratorWorkLoopStruct* iteratorStruct,
1405  bool isFrontEndMacro)
1406 {
1407  sleep(1);
1408 
1409  // Steps:
1410  // 4 parameters CommandExecuteFEMacroParams:
1411  // //targets
1412  // const std::string FEMacroName_ = "FEMacroName";
1413  // //macro parameters (table/groupID)
1414 
1415  const std::string& macroName =
1416  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1417  .params_[IterateTable::commandExecuteMacroParams_.MacroName_];
1418 
1419  __COUTV__(macroName);
1420 
1421  // send request to MacroMaker to check completion of macro
1422  // as targets are identified complete, remove targets_ from vector
1423 
1424  for(unsigned int i = 0;
1425  i < iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.size();
1426  ++i)
1427  {
1429  iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_[i];
1430 
1431  __COUT__ << "target " << target.table_ << ":" << target.UID_ << __E__;
1432 
1433  xoap::MessageReference message =
1434  SOAPUtilities::makeSOAPMessageReference("FECommunication");
1435 
1436  SOAPParameters parameters;
1437  std::string type = isFrontEndMacro ? "feMacroMultiDimensionalCheck"
1438  : "macroMultiDimensionalCheck";
1439  parameters.addParameter("type", type);
1440  parameters.addParameter("requester", WebUsers::DEFAULT_ITERATOR_USERNAME);
1441  parameters.addParameter("targetInterfaceID", target.UID_);
1442  parameters.addParameter(isFrontEndMacro ? "feMacroName" : "macroName", macroName);
1443  SOAPUtilities::addParameters(message, parameters);
1444 
1445  __COUT__ << "Sending FE communication: " << SOAPUtilities::translate(message)
1446  << __E__;
1447 
1448  xoap::MessageReference replyMessage =
1449  iteratorStruct->theIterator_->theSupervisor_
1450  ->SOAPMessenger::sendWithSOAPReply(
1451  iteratorStruct->theIterator_->theSupervisor_->allSupervisorInfo_
1452  .getAllMacroMakerTypeSupervisorInfo()
1453  .begin()
1454  ->second.getDescriptor(),
1455  message);
1456 
1457  __COUT__ << "Response received: " << SOAPUtilities::translate(replyMessage)
1458  << __E__;
1459 
1460  SOAPParameters rxParameters;
1461  rxParameters.addParameter("Error");
1462  rxParameters.addParameter("Done");
1463  std::string response = SOAPUtilities::receive(replyMessage, rxParameters);
1464 
1465  std::string error = rxParameters.getValue("Error");
1466  bool done = rxParameters.getValue("Done") == "1";
1467 
1468  if(response != type + "Done" || error != "")
1469  {
1470  // error occurred!
1471  __SS__ << "Error transmitting request to target interface '" << target.UID_
1472  << "' from '" << WebUsers::DEFAULT_ITERATOR_USERNAME << ".' Response '"
1473  << response << "' with error: " << error << __E__;
1474  __SS_THROW__;
1475  }
1476 
1477  if(!done) // still more to do so give up checking
1478  return false;
1479 
1480  // mark target done
1481  iteratorStruct->targetsDone_[i] = true;
1482 
1483  // iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.erase(
1484  // targetIt--); //go back after delete
1485 
1486  } // end target loop
1487 
1488  // if here all targets are done
1489  return true;
1490 } // end checkCommandMacro()
1491 
1492 //==============================================================================
1493 void Iterator::startCommandModifyActive(IteratorWorkLoopStruct* iteratorStruct)
1494 {
1495  // Steps:
1496  // 4 parameters commandModifyActiveParams_:
1497  // const std::string DoTrackGroupChanges_ TrueFalse
1498  // //targets
1499  // const std::string RelativePathToField_ = "RelativePathToField";
1500  // const std::string FieldStartValue_ = "FieldStartValue";
1501  // const std::string FieldIterationStepSize_ = "FieldIterationStepSize";
1502  //
1503  // if tracking changes,
1504  // create a new group
1505  // for every enabled FE
1506  // set field = start value + stepSize * currentStepIndex_
1507  // activate group
1508  // else
1509  // load scratch group
1510  // for every enabled FE
1511  // set field = start value + stepSize * stepIndex
1512  // activate group
1513 
1514  bool doTrackGroupChanges = false;
1515  if("True" ==
1516  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1517  .params_[IterateTable::commandModifyActiveParams_.DoTrackGroupChanges_])
1518  doTrackGroupChanges = true;
1519 
1520  const std::string& startValueStr =
1521  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1522  .params_[IterateTable::commandModifyActiveParams_.FieldStartValue_];
1523  const std::string& stepSizeStr =
1524  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1525  .params_[IterateTable::commandModifyActiveParams_.FieldIterationStepSize_];
1526 
1527  const unsigned int stepIndex = iteratorStruct->stepIndexStack_.back();
1528 
1529  __COUT__ << "doTrackGroupChanges " << (doTrackGroupChanges ? "yes" : "no")
1530  << std::endl;
1531  __COUTV__(startValueStr);
1532  __COUTV__(stepSizeStr);
1533  __COUTV__(stepIndex);
1534 
1535  ConfigurationInterface::setVersionTrackingEnabled(doTrackGroupChanges);
1536 
1537  // two approaches: double or long handling
1538  // OR TODO -- if step is 0 and startValue is NaN.. then handle as string
1539 
1540  if(((stepSizeStr.size() && stepSizeStr[0] == '0') || !stepSizeStr.size()) &&
1542  startValueStr)) //if not a number and no step size, then interpret as string
1543  {
1544  __COUT__ << "Treating start value as string: " << startValueStr << __E__;
1545  helpCommandModifyActive(iteratorStruct, startValueStr, doTrackGroupChanges);
1546  }
1547  else if(startValueStr.size() && (startValueStr[startValueStr.size() - 1] == 'f' ||
1548  startValueStr.find('.') != std::string::npos))
1549  {
1550  // handle as double
1551  double startValue = strtod(startValueStr.c_str(), 0);
1552  double stepSize = strtod(stepSizeStr.c_str(), 0);
1553 
1554  __COUT__ << "startValue " << startValue << std::endl;
1555  __COUT__ << "stepSize " << stepSize << std::endl;
1556  __COUT__ << "currentValue " << startValue + stepSize * stepIndex << std::endl;
1557 
1558  helpCommandModifyActive(
1559  iteratorStruct, startValue + stepSize * stepIndex, doTrackGroupChanges);
1560  }
1561  else // handle as long
1562  {
1563  long int startValue;
1564  long int stepSize;
1565 
1566  StringMacros::getNumber(startValueStr, startValue);
1567  StringMacros::getNumber(startValueStr, stepSize);
1568 
1569  __COUT__ << "startValue " << startValue << std::endl;
1570  __COUT__ << "stepSize " << stepSize << std::endl;
1571  __COUT__ << "currentValue " << startValue + stepSize * stepIndex << std::endl;
1572 
1573  helpCommandModifyActive(
1574  iteratorStruct, startValue + stepSize * stepIndex, doTrackGroupChanges);
1575  }
1576 
1577 } // end startCommandModifyActive()
1578 
1579 //==============================================================================
1588 bool Iterator::checkCommandRun(IteratorWorkLoopStruct* iteratorStruct)
1589 {
1590  sleep(1); // sleep to give FSM time to transition
1591 
1592  // all RunControlStateMachine access commands should be mutually exclusive with
1593  // GatewaySupervisor main thread state machine accesses should be mutually exclusive
1594  // with GatewaySupervisor main thread state machine accesses lockout the messages
1595  // array for the remainder of the scope this guarantees the reading thread can safely
1596  // access the messages
1597  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
1598  __COUT__ << "Waiting for FSM access" << __E__;
1599  std::lock_guard<std::mutex> lock(
1600  iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_);
1601  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
1602  __COUT__ << "Have FSM access" << __E__;
1603 
1604  if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition())
1605  return false;
1606 
1607  iteratorStruct->fsmCommandParameters_.clear();
1608 
1609  std::string errorStr = "";
1610  std::string currentState = iteratorStruct->theIterator_->theSupervisor_
1611  ->theStateMachine_.getCurrentStateName();
1612 
1614  // check for imposed actions and forced exits
1615  if(iteratorStruct->doPauseAction_)
1616  {
1617  // transition to pause state
1618  __COUT__ << "Transitioning FSM to Paused..." << __E__;
1619 
1620  if(currentState == "Paused")
1621  {
1622  // done with early pause exit!
1623  __COUT__ << "Transition to Paused complete." << __E__;
1624  return true;
1625  }
1626  else if(currentState == "Running") // launch transition to pause
1627  errorStr = iteratorStruct->theIterator_->theSupervisor_
1628  ->attemptStateMachineTransition(
1629  0,
1630  0,
1631  "Pause",
1632  iteratorStruct->fsmName_,
1633  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1634  WebUsers::DEFAULT_ITERATOR_USERNAME,
1635  iteratorStruct->fsmCommandParameters_);
1636  else if(currentState == "Configured")
1637  {
1638  // no need to pause state machine, no run going on
1639  __COUT__ << "In Configured state. No need to transition to Paused." << __E__;
1640  return true;
1641  }
1642  else
1643  errorStr = "Expected to be in Paused. Unexpectedly, the current state is " +
1644  currentState +
1645  ". Last State Machine error message was as follows: " +
1646  iteratorStruct->theIterator_->theSupervisor_->theStateMachine_
1647  .getErrorMessage();
1648 
1649  if(errorStr != "")
1650  {
1651  __SS__ << "Iterator failed to pause because of the following error: "
1652  << errorStr;
1653  __SS_THROW__;
1654  }
1655  return false;
1656  }
1657  else if(iteratorStruct->doHaltAction_)
1658  {
1659  // transition to halted state
1660  __COUT__ << "Transitioning FSM to Halted..." << __E__;
1661 
1662  if(currentState == RunControlStateMachine::HALTED_STATE_NAME)
1663  {
1664  // done with early halt exit!
1665  __COUT__ << "Transition to Halted complete." << __E__;
1666  return true;
1667  }
1668  else if(currentState == RunControlStateMachine::
1669  RUNNING_STATE_NAME || // launch transition to halt
1670  currentState == RunControlStateMachine::PAUSED_STATE_NAME)
1671  errorStr = iteratorStruct->theIterator_->theSupervisor_
1672  ->attemptStateMachineTransition(
1673  0,
1674  0,
1675  RunControlStateMachine::ABORT_TRANSITION_NAME,
1676  iteratorStruct->fsmName_,
1677  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1678  WebUsers::DEFAULT_ITERATOR_USERNAME,
1679  iteratorStruct->fsmCommandParameters_);
1680  else if(currentState == RunControlStateMachine::
1681  CONFIGURED_STATE_NAME) // launch transition to halt
1682  errorStr = iteratorStruct->theIterator_->theSupervisor_
1683  ->attemptStateMachineTransition(
1684  0,
1685  0,
1686  RunControlStateMachine::HALT_TRANSITION_NAME,
1687  iteratorStruct->fsmName_,
1688  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1689  WebUsers::DEFAULT_ITERATOR_USERNAME,
1690  iteratorStruct->fsmCommandParameters_);
1691  else
1692  errorStr = "Expected to be in Halted. Unexpectedly, the current state is " +
1693  currentState +
1694  ". Last State Machine error message was as follows: " +
1695  iteratorStruct->theIterator_->theSupervisor_->theStateMachine_
1696  .getErrorMessage();
1697 
1698  if(errorStr != "")
1699  {
1700  __SS__ << "Iterator failed to halt because of the following error: "
1701  << errorStr;
1702  __SS_THROW__;
1703  }
1704  return false;
1705  }
1706  else if(iteratorStruct->doResumeAction_)
1707  {
1708  // Note: check command gets one shot to resume
1709 
1710  // transition to running state
1711  __COUT__ << "Transitioning FSM to Running..." << __E__;
1712 
1713  if(currentState == "Paused") // launch transition to running
1714  errorStr = iteratorStruct->theIterator_->theSupervisor_
1715  ->attemptStateMachineTransition(
1716  0,
1717  0,
1718  RunControlStateMachine::RESUME_TRANSITION_NAME,
1719  iteratorStruct->fsmName_,
1720  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1721  WebUsers::DEFAULT_ITERATOR_USERNAME,
1722  iteratorStruct->fsmCommandParameters_);
1723 
1724  if(errorStr != "")
1725  {
1726  __SS__ << "Iterator failed to run because of the following error: "
1727  << errorStr;
1728  __SS_THROW__;
1729  }
1730  return false;
1731  }
1732 
1734  // normal running
1735 
1736  if(currentState != "Running")
1737  {
1738  if(iteratorStruct->runIsDone_ && currentState == "Configured")
1739  {
1740  // indication of done
1741  __COUT__ << "Reached end of run " << iteratorStruct->fsmNextRunNumber_
1742  << __E__;
1743  return true;
1744  }
1745 
1746  errorStr = "Expected to be in Running. Unexpectedly, the current state is " +
1747  currentState + ". Last State Machine error message was as follows: " +
1748  iteratorStruct->theIterator_->theSupervisor_->theStateMachine_
1749  .getErrorMessage();
1750  }
1751  else // else in Running state! Check for end of run
1752  {
1753  bool waitOnRunningThreads = false;
1754  if("True" == iteratorStruct->commands_[iteratorStruct->commandIndex_]
1755  .params_[IterateTable::commandRunParams_.WaitOnRunningThreads_])
1756  waitOnRunningThreads = true;
1757 
1758  time_t remainingDurationInSeconds;
1759  sscanf(iteratorStruct->commands_[iteratorStruct->commandIndex_]
1760  .params_[IterateTable::commandRunParams_.DurationInSeconds_]
1761  .c_str(),
1762  "%ld",
1763  &remainingDurationInSeconds);
1764 
1765  __COUT__ << "waitOnRunningThreads " << waitOnRunningThreads << __E__;
1766  __COUT__ << "remainingDurationInSeconds " << remainingDurationInSeconds << __E__;
1767 
1769  // priority 1 is waiting on running threads
1770  if(waitOnRunningThreads)
1771  {
1772  // get status of all running FE workloops
1773  GatewaySupervisor* theSupervisor =
1774  iteratorStruct->theIterator_->theSupervisor_;
1775 
1776  bool allFrontEndsAreDone = true;
1777  for(auto& it : theSupervisor->allSupervisorInfo_.getAllFETypeSupervisorInfo())
1778  {
1779  try
1780  {
1781  std::string status = theSupervisor->send(it.second.getDescriptor(),
1782  "WorkLoopStatusRequest");
1783 
1784  __COUT__ << "FESupervisor instance " << it.first
1785  << " has status = " << status << std::endl;
1786 
1787  if(status != CoreSupervisorBase::WORK_LOOP_DONE)
1788  {
1789  allFrontEndsAreDone = false;
1790  break;
1791  }
1792  }
1793  catch(xdaq::exception::Exception& e)
1794  {
1795  __SS__ << "Could not retrieve status from FESupervisor instance "
1796  << it.first << "." << std::endl;
1797  __COUT_WARN__ << ss.str();
1798  errorStr = ss.str();
1799 
1800  if(errorStr != "")
1801  {
1802  __SS__
1803  << "Iterator failed to run because of the following error: "
1804  << errorStr;
1805  __SS_THROW__;
1806  }
1807  }
1808  }
1809 
1810  if(allFrontEndsAreDone)
1811  {
1812  // need to end run!
1813  __COUT__ << "FE workloops all complete! Stopping run..." << __E__;
1814 
1815  errorStr = iteratorStruct->theIterator_->theSupervisor_
1816  ->attemptStateMachineTransition(
1817  0,
1818  0,
1819  "Stop",
1820  iteratorStruct->fsmName_,
1821  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1822  WebUsers::DEFAULT_ITERATOR_USERNAME,
1823  iteratorStruct->fsmCommandParameters_);
1824 
1825  if(errorStr != "")
1826  {
1827  __SS__
1828  << "Iterator failed to stop run because of the following error: "
1829  << errorStr;
1830  __SS_THROW__;
1831  }
1832 
1833  // write indication of run done into duration
1834  iteratorStruct->runIsDone_ = true;
1835 
1836  return false;
1837  }
1838  } //end waitOnRunningThreads
1839 
1841  // priority 2 is duration, if <= 0 it is ignored
1842  if(remainingDurationInSeconds > 1)
1843  {
1844  //reset command start time (for displays) once running is stable
1845  if(remainingDurationInSeconds == iteratorStruct->originalDurationInSeconds_)
1846  {
1847  iteratorStruct->theIterator_->activeCommandStartTime_ =
1848  time(0); // reset on any change
1849  __COUT__ << "Starting run duration of " << remainingDurationInSeconds
1850  << " [s] at time = "
1851  << iteratorStruct->theIterator_->activeCommandStartTime_ << " "
1853  iteratorStruct->theIterator_->activeCommandStartTime_)
1854  << __E__;
1855  }
1856 
1857  --remainingDurationInSeconds;
1858 
1859  // write back to string
1860  char str[200];
1861  sprintf(str, "%ld", remainingDurationInSeconds);
1862  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1863  .params_[IterateTable::commandRunParams_.DurationInSeconds_] =
1864  str; // re-store as string
1865  }
1866  else if(remainingDurationInSeconds == 1)
1867  {
1868  // need to end run!
1869  __COUT__ << "Time duration reached! Stopping run..." << __E__;
1870 
1871  errorStr = iteratorStruct->theIterator_->theSupervisor_
1872  ->attemptStateMachineTransition(
1873  0,
1874  0,
1875  "Stop",
1876  iteratorStruct->fsmName_,
1877  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1878  WebUsers::DEFAULT_ITERATOR_USERNAME,
1879  iteratorStruct->fsmCommandParameters_);
1880 
1881  if(errorStr != "")
1882  {
1883  __SS__ << "Iterator failed to stop run because of the following error: "
1884  << errorStr;
1885  __SS_THROW__;
1886  }
1887 
1888  // write indication of run done
1889  iteratorStruct->runIsDone_ = true;
1890 
1891  // write original duration back to string
1892  char str[200];
1893  sprintf(str, "%ld", iteratorStruct->originalDurationInSeconds_);
1894  iteratorStruct->commands_[iteratorStruct->commandIndex_]
1895  .params_[IterateTable::commandRunParams_.DurationInSeconds_] =
1896  str; // re-store as string
1897  return false;
1898  }
1899  }
1900 
1901  if(errorStr != "")
1902  {
1903  __SS__ << "Iterator failed to run because of the following error: " << errorStr;
1904  __SS_THROW__;
1905  }
1906  return false;
1907 } // end checkCommandRun()
1908 
1909 //==============================================================================
1911 bool Iterator::checkCommandConfigure(IteratorWorkLoopStruct* iteratorStruct)
1912 {
1913  sleep(1); // sleep to give FSM time to transition
1914 
1915  // all RunControlStateMachine access commands should be mutually exclusive with
1916  // GatewaySupervisor main thread state machine accesses should be mutually exclusive
1917  // with GatewaySupervisor main thread state machine accesses lockout the messages
1918  // array for the remainder of the scope this guarantees the reading thread can safely
1919  // access the messages
1920  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
1921  __COUT__ << "Waiting for FSM access" << __E__;
1922  std::lock_guard<std::mutex> lock(
1923  iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_);
1924  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
1925  __COUT__ << "Have FSM access" << __E__;
1926 
1927  if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition())
1928  return false;
1929 
1930  std::string errorStr = "";
1931  std::string currentState = iteratorStruct->theIterator_->theSupervisor_
1932  ->theStateMachine_.getCurrentStateName();
1933 
1934  if(currentState == RunControlStateMachine::HALTED_STATE_NAME)
1935  errorStr =
1936  iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition(
1937  0,
1938  0,
1939  "Configure",
1940  iteratorStruct->fsmName_,
1941  WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/,
1942  WebUsers::DEFAULT_ITERATOR_USERNAME,
1943  iteratorStruct->fsmCommandParameters_);
1944  else if(currentState != RunControlStateMachine::CONFIGURED_STATE_NAME)
1945  errorStr = "Expected to be in '" + RunControlStateMachine::CONFIGURED_STATE_NAME +
1946  "' state. Unexpectedly, the current state is " + currentState + "." +
1947  ". Last State Machine error message was as follows: " +
1948  iteratorStruct->theIterator_->theSupervisor_->theStateMachine_
1949  .getErrorMessage();
1950  else // else successfully done (in Configured state!)
1951  {
1952  __COUT__ << "checkCommandConfigureAlias complete." << __E__;
1953 
1954  // also activate the Iterator config manager to mimic active config
1955  std::pair<std::string, TableGroupKey> newActiveGroup =
1956  iteratorStruct->cfgMgr_->getTableGroupFromAlias(
1957  iteratorStruct->fsmCommandParameters_[0]);
1958  iteratorStruct->cfgMgr_->loadTableGroup(
1959  newActiveGroup.first, newActiveGroup.second, true /*activate*/);
1960 
1961  __COUT__ << "originalTrackChanges " << iteratorStruct->originalTrackChanges_
1962  << __E__;
1963  __COUT__ << "originalConfigGroup " << iteratorStruct->originalConfigGroup_
1964  << __E__;
1965  __COUT__ << "originalConfigKey " << iteratorStruct->originalConfigKey_ << __E__;
1966 
1967  __COUT__ << "currentTrackChanges "
1968  << ConfigurationInterface::isVersionTrackingEnabled() << __E__;
1969  __COUT__ << "originalConfigGroup "
1970  << iteratorStruct->cfgMgr_->getActiveGroupName() << __E__;
1971  __COUT__ << "originalConfigKey " << iteratorStruct->cfgMgr_->getActiveGroupKey()
1972  << __E__;
1973 
1974  return true;
1975  }
1976 
1977  if(errorStr != "")
1978  {
1979  __SS__ << "Iterator failed to configure with system alias '"
1980  << (iteratorStruct->fsmCommandParameters_.size()
1981  ? iteratorStruct->fsmCommandParameters_[0]
1982  : "UNKNOWN")
1983  << "' because of the following error: " << errorStr;
1984  __SS_THROW__;
1985  }
1986  return false;
1987 } // end checkCommandConfigure()
1988 
1989 //==============================================================================
1991 bool Iterator::checkCommandFSMTransition(IteratorWorkLoopStruct* iteratorStruct,
1992  const std::string& finalState)
1993 {
1994  __COUTV__(finalState);
1995 
1996  sleep(1); // sleep to give FSM time to transition
1997 
1998  // all RunControlStateMachine access commands should be mutually exclusive with
1999  // GatewaySupervisor main thread state machine accesses should be mutually exclusive
2000  // with GatewaySupervisor main thread state machine accesses lockout the messages
2001  // array for the remainder of the scope this guarantees the reading thread can safely
2002  // access the messages
2003  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
2004  __COUT__ << "Waiting for FSM access" << __E__;
2005  std::lock_guard<std::mutex> lock(
2006  iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_);
2007  if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX)
2008  __COUT__ << "Have FSM access" << __E__;
2009 
2010  if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition())
2011  return false;
2012 
2013  std::string errorStr = "";
2014  std::string currentState = iteratorStruct->theIterator_->theSupervisor_
2015  ->theStateMachine_.getCurrentStateName();
2016 
2017  if(currentState != finalState)
2018  errorStr = "Expected to be in " + finalState +
2019  ". Unexpectedly, the current state is " + currentState + "." +
2020  ". Last State Machine error message was as follows: " +
2021  iteratorStruct->theIterator_->theSupervisor_->theStateMachine_
2022  .getErrorMessage();
2023  else // else successfully done (in Configured state!)
2024  {
2025  __COUT__ << "checkCommandFSMTransition complete." << __E__;
2026 
2027  return true;
2028  }
2029 
2030  if(errorStr != "")
2031  {
2032  __SS__ << "Iterator failed to reach final state '" << finalState
2033  << "' because of the following error: " << errorStr;
2034  __SS_THROW__;
2035  }
2036  return false;
2037 } // end checkCommandConfigure()
2038 
2039 //==============================================================================
2041 std::vector<IterateTable::Command> Iterator::generateIterationPlan(
2042  const std::string& fsmName,
2043  const std::string& configAlias,
2044  uint64_t durationSeconds /* = -1 */,
2045  unsigned int numberOfRuns /* = 1 */)
2046 {
2047  std::vector<IterateTable::Command> commands;
2048 
2049  //example commands:
2050  // Choose FSM name
2051  // Configure if needed to selected system alias
2052  // Start run
2053  // count seconds
2054  // Stop run numberOfRuns
2055  // loop
2056 
2057  if(durationSeconds == (uint64_t)-1)
2058  numberOfRuns = 1;
2059  __COUTV__(durationSeconds);
2060  __COUTV__(numberOfRuns);
2061 
2062  // -------- Choose FSM name
2063  {
2064  commands.push_back(IterateTable::Command());
2065  commands.back().type_ = IterateTable::COMMAND_CHOOSE_FSM;
2066 
2067  commands.back().params_.emplace(
2068  std::pair<std::string /*param name*/, std::string /*param value*/>(
2069  IterateTable::commandChooseFSMParams_.NameOfFSM_, fsmName));
2070  }
2071 
2072  // -------- Configure if needed to selected system alias
2073  {
2074  commands.push_back(IterateTable::Command());
2075  commands.back().type_ = IterateTable::COMMAND_CONFIGURE_ALIAS;
2076 
2077  commands.back().params_.emplace(
2078  std::pair<std::string /*param name*/, std::string /*param value*/>(
2079  IterateTable::commandConfigureAliasParams_.SystemAlias_, configAlias));
2080  }
2081 
2082  if(durationSeconds == (uint64_t)-1)
2083  {
2084  __COUT__ << "Open ended run..." << __E__;
2085 
2086  // -------- Start FSM transtion
2087  {
2088  commands.push_back(IterateTable::Command());
2089  commands.back().type_ = IterateTable::COMMAND_START;
2090  }
2091  }
2092  else
2093  {
2094  __COUT__ << "Finite duration run(s)..." << __E__;
2095 
2096  if(numberOfRuns > 1)
2097  {
2098  __COUT__ << "Setting up iterator loop for " << numberOfRuns << " runs."
2099  << __E__;
2100 
2101  commands.push_back(IterateTable::Command());
2102  commands.back().type_ = IterateTable::COMMAND_BEGIN_LABEL;
2103 
2104  commands.back().params_.emplace(
2105  std::pair<std::string /*param name*/, std::string /*param value*/>(
2106  IterateTable::commandBeginLabelParams_.Label_, "GENERATED_LABEL"));
2107  }
2108 
2109  // -------- Start managed run
2110  {
2111  commands.push_back(IterateTable::Command());
2112  commands.back().type_ = IterateTable::COMMAND_RUN;
2113 
2114  commands.back().params_.emplace(
2115  std::pair<std::string /*param name*/, std::string /*param value*/>(
2116  IterateTable::commandRunParams_.DurationInSeconds_,
2117  std::to_string(durationSeconds)));
2118  }
2119 
2120  if(numberOfRuns > 1)
2121  {
2122  commands.push_back(IterateTable::Command());
2123  commands.back().type_ = IterateTable::COMMAND_REPEAT_LABEL;
2124 
2125  commands.back().params_.emplace(
2126  std::pair<std::string /*param name*/, std::string /*param value*/>(
2127  IterateTable::commandRepeatLabelParams_.Label_, "GENERATED_LABEL"));
2128  commands.back().params_.emplace(
2129  std::pair<std::string /*param name*/, std::string /*param value*/>(
2130  IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_,
2131  std::to_string(numberOfRuns -
2132  1) //number of repeats (i.e., 1 repeat, gives 2 runs)
2133  ));
2134  }
2135  }
2136 
2137  __COUTV__(commands.size());
2138 
2139  return commands;
2140 } //end generateIterationPlan()
2141 
2142 //==============================================================================
2143 bool Iterator::handleCommandRequest(HttpXmlDocument& xmldoc,
2144  const std::string& command,
2145  const std::string& parameter)
2146 try
2147 {
2148  //__COUTV__(command);
2149  if(command == "iteratePlay")
2150  {
2151  playIterationPlan(xmldoc, parameter);
2152  return true;
2153  }
2154  else if(command == "iteratePlayGenerated")
2155  {
2156  playGeneratedIterationPlan(xmldoc, parameter);
2157  return true;
2158  }
2159  else if(command == "iteratePause")
2160  {
2161  pauseIterationPlan(xmldoc);
2162  return true;
2163  }
2164  else if(command == "iterateHalt")
2165  {
2166  haltIterationPlan(xmldoc);
2167  return true;
2168  }
2169  else if(command == "getIterationPlanStatus")
2170  {
2171  if(activePlanName_ == "" &&
2172  parameter !=
2173  "") //take parameter to set active plan name from GUI manipulations
2174  {
2175  activePlanName_ = parameter;
2176  __COUTV__(activePlanName_);
2177  }
2178  getIterationPlanStatus(xmldoc);
2179  return true;
2180  }
2181  else // return true if iterator has control of state machine
2182  {
2183  // lockout the messages array for the remainder of the scope
2184  // this guarantees the reading thread can safely access the messages
2185  if(theSupervisor_->VERBOSE_MUTEX)
2186  __COUT__ << "Waiting for iterator access" << __E__;
2187  std::lock_guard<std::mutex> lock(accessMutex_);
2188  if(theSupervisor_->VERBOSE_MUTEX)
2189  __COUT__ << "Have iterator access" << __E__;
2190 
2191  if(iteratorBusy_)
2192  {
2193  __SS__ << "Error - Can not accept request because the Iterator "
2194  << "is currently "
2195  << "in control of State Machine progress. ";
2196  __COUT_ERR__ << "\n" << ss.str();
2197  __COUT_ERR__ << "\n" << ss.str();
2198 
2199  xmldoc.addTextElementToData("state_tranisition_attempted",
2200  "0"); // indicate to GUI transition NOT attempted
2201  xmldoc.addTextElementToData(
2202  "state_tranisition_attempted_err",
2203  ss.str()); // indicate to GUI transition NOT attempted
2204  theSupervisor_->theStateMachine_.setErrorMessage(ss.str());
2205  return true; // to block other commands
2206  }
2207  }
2208  return false;
2209 } //end handleCommandRequest()
2210 catch(...)
2211 {
2212  __SS__ << "Error caught by Iterator command handling!" << __E__;
2213  try
2214  {
2215  throw;
2216  }
2217  catch(const std::runtime_error& e)
2218  {
2219  ss << "\nHere is the error: " << e.what() << __E__;
2220  }
2221  catch(...)
2222  {
2223  ss << "Uknown error caught." << __E__;
2224  }
2225 
2226  __COUT_ERR__ << "\n" << ss.str();
2227 
2228  xmldoc.addTextElementToData("state_tranisition_attempted",
2229  "0"); // indicate to GUI transition NOT attempted
2230  xmldoc.addTextElementToData("state_tranisition_attempted_err",
2231  ss.str()); // indicate to GUI transition NOT attempted
2232  theSupervisor_->theStateMachine_.setErrorMessage(ss.str());
2233  return true;
2234 } // end handleCommandRequest() error handling
2235 
2236 //==============================================================================
2237 void Iterator::playIterationPlan(HttpXmlDocument& xmldoc, const std::string& planName)
2238 {
2239  __COUT__ << "Attempting to play iteration plan '" << planName << ".'" << __E__;
2240 
2241  if(planName == Iterator::RESERVED_GEN_PLAN_NAME)
2242  {
2243  __SS__ << "Illegal use of reserved iteration plan name '"
2244  << Iterator::RESERVED_GEN_PLAN_NAME << "!' Please select a different name."
2245  << __E__;
2246  __SS_THROW__;
2247  }
2248 
2249  playIterationPlanPrivate(xmldoc, planName);
2250 
2251 } //end playIterationPlan()
2252 
2253 //==============================================================================
2254 void Iterator::playGeneratedIterationPlan(HttpXmlDocument& xmldoc,
2255  const std::string& parametersCSV)
2256 {
2257  __COUTV__(parametersCSV);
2258  std::vector<std::string> parameters =
2259  StringMacros::getVectorFromString(parametersCSV, {','});
2260 
2261  if(parameters.size() != 6)
2262  {
2263  __SS__ << "Malformed CSV parameters to playGeneratedIterationPlan(), must be 6 "
2264  "arguments and there were "
2265  << parameters.size() << ": " << parametersCSV << __E__;
2266  __SS_THROW__;
2267  }
2268  // parameters[0] /*fsmName*/,
2269  // parameters[1] /*configAlias*/,
2270  // parameters[2] /*durationSeconds*/,
2271  // parameters[3] /*numberOfRuns*/,
2272  // parameters[4] /*keepConfiguration*/,
2273  // parameters[5] /*logEntry*/ double encoded
2274  parameters[5] = StringMacros::decodeURIComponent(parameters[5]);
2275 
2276  uint64_t durationSeconds;
2277  sscanf(parameters[2].c_str(), "%lu", &durationSeconds);
2278  unsigned int numberOfRuns;
2279  sscanf(parameters[3].c_str(), "%u", &numberOfRuns);
2280  unsigned int keepConfiguration;
2281  sscanf(parameters[4].c_str(), "%u", &keepConfiguration);
2282  playGeneratedIterationPlan(xmldoc,
2283  parameters[0] /*fsmName*/,
2284  parameters[1] /*configAlias*/,
2285  durationSeconds,
2286  numberOfRuns,
2287  keepConfiguration,
2288  parameters[5] /*logEntry*/
2289  );
2290 
2291 } //end playGeneratedIterationPlan()
2292 
2293 //==============================================================================
2294 void Iterator::playGeneratedIterationPlan(HttpXmlDocument& xmldoc,
2295  const std::string& fsmName,
2296  const std::string& configAlias,
2297  uint64_t durationSeconds /* = -1 */,
2298  unsigned int numberOfRuns /* = 1 */,
2299  bool keepConfiguration /* = false */,
2300  const std::string& logEntry)
2301 {
2302  std::string planName = Iterator::RESERVED_GEN_PLAN_NAME;
2303  __COUT__ << "Attempting to play iteration plan '" << planName << ".'" << __E__;
2304 
2305  genFsmName_ = fsmName;
2306  genConfigAlias_ = configAlias;
2307  genPlanDurationSeconds_ = durationSeconds;
2308  genPlanNumberOfRuns_ = numberOfRuns;
2309  genKeepConfiguration_ = keepConfiguration;
2310  genLogEntry_ = logEntry;
2311 
2312  __COUTV__(genFsmName_);
2313  __COUTV__(genConfigAlias_);
2314  __COUTV__(genPlanDurationSeconds_);
2315  __COUTV__(genPlanNumberOfRuns_);
2316  __COUTV__(genKeepConfiguration_);
2317  __COUTV__(genLogEntry_);
2318 
2319  playIterationPlanPrivate(xmldoc, planName);
2320 
2321 } //end playGeneratedIterationPlan()
2322 
2323 //==============================================================================
2325 void Iterator::playIterationPlanPrivate(HttpXmlDocument& xmldoc,
2326  const std::string& planName)
2327 {
2328  // setup "play" command
2329 
2330  // lockout the messages array for the remainder of the scope
2331  // this guarantees the reading thread can safely access the messages
2332  if(theSupervisor_->VERBOSE_MUTEX)
2333  __COUT__ << "Waiting for iterator access" << __E__;
2334  std::lock_guard<std::mutex> lock(accessMutex_);
2335  if(theSupervisor_->VERBOSE_MUTEX)
2336  __COUT__ << "Have iterator access" << __E__;
2337 
2338  if(!activePlanIsRunning_ && !commandPlay_)
2339  {
2340  if(!workloopRunning_)
2341  {
2342  // start thread with member variables initialized
2343 
2344  workloopRunning_ = true;
2345 
2346  // must start thread first
2347  std::thread([](Iterator* iterator) { Iterator::IteratorWorkLoop(iterator); },
2348  this)
2349  .detach();
2350  }
2351 
2352  activePlanName_ = planName;
2353  commandPlay_ = true;
2354  }
2355  else
2356  {
2357  __SS__ << "Invalid play command attempted. Can only play when the Iterator is "
2358  "inactive or paused."
2359  << " If you would like to restart an iteration plan, first try halting "
2360  "the Iterator."
2361  << __E__;
2362  __COUT__ << ss.str();
2363 
2364  xmldoc.addTextElementToData("error_message", ss.str());
2365 
2366  __COUT__ << "Invalid play command attempted. " << activePlanIsRunning_ << " "
2367  << commandPlay_ << " " << activePlanName_ << __E__;
2368  }
2369 } //end playIterationPlan()
2370 
2371 //==============================================================================
2372 void Iterator::pauseIterationPlan(HttpXmlDocument& xmldoc)
2373 {
2374  __COUT__ << "Attempting to pause iteration plan '" << activePlanName_ << ".'"
2375  << __E__;
2376  __COUT__ << "Attempting to pause iteration plan '" << activePlanName_ << ".'"
2377  << __E__;
2378 
2379  // setup "pause" command
2380 
2381  // lockout the messages array for the remainder of the scope
2382  // this guarantees the reading thread can safely access the messages
2383  if(theSupervisor_->VERBOSE_MUTEX)
2384  __COUT__ << "Waiting for iterator access" << __E__;
2385  std::lock_guard<std::mutex> lock(accessMutex_);
2386  if(theSupervisor_->VERBOSE_MUTEX)
2387  __COUT__ << "Have iterator access" << __E__;
2388 
2389  if(workloopRunning_ && activePlanIsRunning_ && !commandPause_)
2390  {
2391  commandPause_ = true;
2392  }
2393  else
2394  {
2395  __SS__ << "Invalid pause command attempted. Can only pause when running."
2396  << __E__;
2397  __COUT__ << ss.str();
2398 
2399  xmldoc.addTextElementToData("error_message", ss.str());
2400 
2401  __COUT__ << "Invalid pause command attempted. " << workloopRunning_ << " "
2402  << activePlanIsRunning_ << " " << commandPause_ << " " << activePlanName_
2403  << __E__;
2404  }
2405 } //end pauseIterationPlan()
2406 
2407 //==============================================================================
2408 void Iterator::haltIterationPlan(HttpXmlDocument& /*xmldoc*/)
2409 {
2410  __COUT__ << "Attempting to halt iteration plan '" << activePlanName_ << ".'" << __E__;
2411  __COUT__ << "Attempting to halt iteration plan '" << activePlanName_ << ".'" << __E__;
2412 
2413  // setup "halt" command
2414 
2415  if(workloopRunning_)
2416  {
2417  // lockout the messages array for the remainder of the scope
2418  // this guarantees the reading thread can safely access the messages
2419  if(theSupervisor_->VERBOSE_MUTEX)
2420  __COUT__ << "Waiting for iterator access" << __E__;
2421  std::lock_guard<std::mutex> lock(accessMutex_);
2422  if(theSupervisor_->VERBOSE_MUTEX)
2423  __COUT__ << "Have iterator access" << __E__;
2424 
2425  __COUT__ << "activePlanIsRunning_: " << activePlanIsRunning_ << __E__;
2426  __COUT__ << "Passing halt command to iterator thread." << __E__;
2427  commandHalt_ = true;
2428 
2429  // clear
2430  activePlanName_ = "";
2431  activeCommandIndex_ = -1;
2432  }
2433  else // no thread, so halt (and reset Error') without command to thread
2434  {
2435  __COUT__ << "No thread, so conducting halt." << __E__;
2436  Iterator::haltIterator(this);
2437  }
2438 } //end haltIterationPlan()
2439 
2440 //==============================================================================
2443 {
2444  xmldoc.addTextElementToData(
2445  "current_state",
2446  theSupervisor_->theStateMachine_.isInTransition()
2447  ? theSupervisor_->theStateMachine_.getCurrentTransitionName(
2448  theSupervisor_->stateMachineLastCommandInput_)
2449  : theSupervisor_->theStateMachine_.getCurrentStateName());
2450 
2451  // xmldoc.addTextElementToData("in_transition",
2452  // theSupervisor_->theStateMachine_.isInTransition() ? "1" : "0");
2453  if(theSupervisor_->theStateMachine_.isInTransition())
2454  xmldoc.addTextElementToData(
2455  "transition_progress",
2456  theSupervisor_->theProgressBar_.readPercentageString());
2457  else
2458  xmldoc.addTextElementToData("transition_progress", "100");
2459 
2460  xmldoc.addNumberElementToData("time_in_state",
2461  theSupervisor_->theStateMachine_.getTimeInState());
2462 
2463  // lockout the messages array for the remainder of the scope
2464  // this guarantees the reading thread can safely access the messages
2465  if(theSupervisor_->VERBOSE_MUTEX)
2466  __COUT__ << "Waiting for iterator access" << __E__;
2467  std::lock_guard<std::mutex> lock(accessMutex_);
2468  if(theSupervisor_->VERBOSE_MUTEX)
2469  __COUT__ << "Have iterator access" << __E__;
2470 
2471  xmldoc.addTextElementToData("active_plan", activePlanName_);
2472  xmldoc.addTextElementToData("last_started_plan", lastStartedPlanName_);
2473  xmldoc.addTextElementToData("last_finished_plan", lastFinishedPlanName_);
2474 
2475  xmldoc.addNumberElementToData("current_command_index", activeCommandIndex_);
2476  xmldoc.addNumberElementToData("current_number_of_commands", activeNumberOfCommands_);
2477  xmldoc.addTextElementToData("current_command_type", activeCommandType_);
2478  xmldoc.addNumberElementToData("current_command_duration",
2479  time(0) - activeCommandStartTime_);
2480  xmldoc.addNumberElementToData("current_command_iteration", activeCommandIteration_);
2481  for(const auto& depthIteration : depthIterationStack_)
2482  xmldoc.addNumberElementToData("depth_iteration", depthIteration);
2483 
2484  if(activePlanName_ == Iterator::RESERVED_GEN_PLAN_NAME)
2485  {
2486  xmldoc.addNumberElementToData("generated_number_of_runs", genPlanNumberOfRuns_);
2487  xmldoc.addNumberElementToData("generated_duration_of_runs",
2488  genPlanDurationSeconds_);
2489  }
2490 
2491  if(activePlanIsRunning_ && iteratorBusy_)
2492  {
2493  if(workloopRunning_)
2494  xmldoc.addTextElementToData("active_plan_status", "Running");
2495  else
2496  xmldoc.addTextElementToData("active_plan_status", "Error");
2497  }
2498  else if(!activePlanIsRunning_ && iteratorBusy_)
2499  xmldoc.addTextElementToData("active_plan_status", "Paused");
2500  else
2501  xmldoc.addTextElementToData("active_plan_status", "Inactive");
2502 
2503  xmldoc.addTextElementToData("error_message", errorMessage_);
2504 } //end getIterationPlanStatus()
void loadTableGroup(const std::string &tableGroupName, const TableGroupKey &tableGroupKey, bool doActivate=false, std::map< std::string, TableVersion > *groupMembers=0, ProgressBar *progressBar=0, std::string *accumulateWarnings=0, std::string *groupComment=0, std::string *groupAuthor=0, std::string *groupCreateTime=0, bool doNotLoadMember=false, std::string *groupTypeString=0, std::map< std::string, std::string > *groupAliases=0, ConfigurationManager::LoadGroupType onlyLoadIfBackboneOrContext=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false)
std::pair< std::string, TableGroupKey > getTableGroupFromAlias(std::string systemAlias, ProgressBar *progressBar=0)
Getters.
bool isDisconnected(void) const
ConfigurationTree getNode(const std::string &nodeName, bool doNotThrowOnBrokenUIDLinks=false) const
navigating between nodes
void getValue(T &value) const
time_t getTimeInState(void) const
static const std::string COMMAND_BEGIN_LABEL
Definition: IterateTable.h:36
void getIterationPlanStatus(HttpXmlDocument &xmldoc)
return state machine and iterator status
Definition: Iterator.cc:2442
std::string readPercentageString()
return percentage complete as std::string
Definition: ProgressBar.cc:136
std::string send(XDAQ_CONST_CALL xdaq::ApplicationDescriptor *d, xoap::MessageReference message)
static std::string getTimestampString(const std::string &linuxTimeInSeconds)
static void getVectorFromString(const std::string &inputString, std::vector< std::string > &listToReturn, const std::set< char > &delimiter={',', '|', '&'}, const std::set< char > &whitespace={' ', '\t', '\n', '\r'}, std::vector< char > *listOfDelimiters=0, bool decodeURIComponents=false)
static std::string vectorToString(const std::vector< T > &setToReturn, const std::string &delimeter=", ")
vectorToString ~
static bool isNumber(const std::string &stringToCheck)
Note: before call consider use of stringToCheck = StringMacros::convertEnvironmentVariables(stringToC...
static std::string decodeURIComponent(const std::string &data)
static bool getNumber(const std::string &s, T &retValue)