$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/GatewaySupervisor/GatewaySupervisor.h" 00002 #include "otsdaq-core/CgiDataUtilities/CgiDataUtilities.h" 00003 #include "otsdaq-core/Macros/CoutMacros.h" 00004 #include "otsdaq-core/MessageFacility/MessageFacility.h" 00005 #include "otsdaq-core/SOAPUtilities/SOAPCommand.h" 00006 #include "otsdaq-core/SOAPUtilities/SOAPUtilities.h" 00007 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h" 00008 00009 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h" 00010 #include "otsdaq-core/ConfigurationInterface/ConfigurationManagerRW.h" 00011 #include "otsdaq-core/GatewaySupervisor/ARTDAQCommandable.h" 00012 #include "otsdaq-core/TablePluginDataFormats/DesktopIconTable.h" 00013 #include "otsdaq-core/TablePluginDataFormats/XDAQContextTable.h" 00014 #include "otsdaq-core/WorkLoopManager/WorkLoopManager.h" 00015 00016 #include "otsdaq-core/NetworkUtilities/TransceiverSocket.h" // for UDP state changer 00017 00018 #include <cgicc/HTMLClasses.h> 00019 #include <cgicc/HTMLDoctype.h> 00020 #include <cgicc/HTTPCookie.h> 00021 #include <cgicc/HTTPHeader.h> 00022 #include <xgi/Utils.h> 00023 00024 #include <toolbox/fsm/FailedEvent.h> 00025 #include <toolbox/task/WorkLoopFactory.h> 00026 #include <xdaq/NamespaceURI.h> 00027 #include <xoap/Method.h> 00028 00029 #include <sys/stat.h> // for mkdir 00030 #include <chrono> // std::chrono::seconds 00031 #include <fstream> 00032 #include <thread> // std::this_thread::sleep_for 00033 00034 using namespace ots; 00035 00036 #define RUN_NUMBER_PATH std::string(getenv("SERVICE_DATA_PATH")) + "/RunNumber/" 00037 #define RUN_NUMBER_FILE_NAME "NextRunNumber.txt" 00038 #define FSM_LAST_GROUP_ALIAS_PATH \ 00039 std::string(getenv("SERVICE_DATA_PATH")) + "/RunControlData/" 00040 #define FSM_LAST_GROUP_ALIAS_FILE_START std::string("FSMLastGroupAlias-") 00041 #define FSM_USERS_PREFERENCES_FILETYPE "pref" 00042 00043 #undef __MF_SUBJECT__ 00044 #define __MF_SUBJECT__ "GatewaySupervisor" 00045 00046 XDAQ_INSTANTIATOR_IMPL(GatewaySupervisor) 00047 00048 //======================================================================================================================== 00049 GatewaySupervisor::GatewaySupervisor(xdaq::ApplicationStub* s) 00050 : xdaq::Application(s) 00051 , SOAPMessenger(this) 00052 , RunControlStateMachine("GatewaySupervisor") 00053 , CorePropertySupervisorBase(this) 00054 //, CorePropertySupervisorBase::theConfigurationManager_(new ConfigurationManager) 00055 //,theConfigurationTableGroupKey_ (nullptr) 00056 , theArtdaqCommandable_(this) 00057 , stateMachineWorkLoopManager_(toolbox::task::bind( 00058 this, &GatewaySupervisor::stateMachineThread, "StateMachine")) 00059 , stateMachineSemaphore_(toolbox::BSem::FULL) 00060 , infoRequestWorkLoopManager_( 00061 toolbox::task::bind(this, &GatewaySupervisor::infoRequestThread, "InfoRequest")) 00062 , infoRequestSemaphore_(toolbox::BSem::FULL) 00063 , activeStateMachineName_("") 00064 , theIterator_(this) 00065 , broadcastCommandMessageIndex_(0) 00066 , counterTest_(0) 00067 { 00068 INIT_MF("GatewaySupervisor"); 00069 __COUT__ << __E__; 00070 00071 // attempt to make directory structure (just in case) 00072 mkdir((std::string(getenv("SERVICE_DATA_PATH"))).c_str(), 0755); 00073 mkdir((FSM_LAST_GROUP_ALIAS_PATH).c_str(), 0755); 00074 mkdir((RUN_NUMBER_PATH).c_str(), 0755); 00075 00076 securityType_ = theWebUsers_.getSecurity(); 00077 00078 __COUT__ << "Security: " << securityType_ << __E__; 00079 00080 xgi::bind(this, &GatewaySupervisor::Default, "Default"); 00081 xgi::bind(this, &GatewaySupervisor::loginRequest, "LoginRequest"); 00082 xgi::bind(this, &GatewaySupervisor::request, "Request"); 00083 xgi::bind(this, &GatewaySupervisor::stateMachineXgiHandler, "StateMachineXgiHandler"); 00084 xgi::bind(this, &GatewaySupervisor::infoRequestHandler, "InfoRequestHandler"); 00085 xgi::bind( 00086 this, &GatewaySupervisor::infoRequestResultHandler, "InfoRequestResultHandler"); 00087 xgi::bind(this, &GatewaySupervisor::tooltipRequest, "TooltipRequest"); 00088 00089 xoap::bind(this, 00090 &GatewaySupervisor::supervisorCookieCheck, 00091 "SupervisorCookieCheck", 00092 XDAQ_NS_URI); 00093 xoap::bind(this, 00094 &GatewaySupervisor::supervisorGetActiveUsers, 00095 "SupervisorGetActiveUsers", 00096 XDAQ_NS_URI); 00097 xoap::bind(this, 00098 &GatewaySupervisor::supervisorSystemMessage, 00099 "SupervisorSystemMessage", 00100 XDAQ_NS_URI); 00101 // xoap::bind(this, &GatewaySupervisor::supervisorGetUserInfo, 00102 // "SupervisorGetUserInfo", XDAQ_NS_URI); 00103 xoap::bind(this, 00104 &GatewaySupervisor::supervisorSystemLogbookEntry, 00105 "SupervisorSystemLogbookEntry", 00106 XDAQ_NS_URI); 00107 xoap::bind(this, 00108 &GatewaySupervisor::supervisorLastConfigGroupRequest, 00109 "SupervisorLastConfigGroupRequest", 00110 XDAQ_NS_URI); 00111 00112 // xoap::bind(this, &GatewaySupervisor::supervisorHandleAsyncError, 00113 // "FERunningError", XDAQ_NS_URI); 00114 00115 init(); 00116 00117 // exit(1); //keep for syntax to exit ots 00118 00119 } // end constructor 00120 00121 //======================================================================================================================== 00122 // TODO: Lore needs to detect program quit through killall or ctrl+c so that Logbook 00123 // entry is made when ots is halted 00124 GatewaySupervisor::~GatewaySupervisor(void) 00125 { 00126 delete CorePropertySupervisorBase::theConfigurationManager_; 00127 makeSystemLogbookEntry("ots halted."); 00128 } // end destructor 00129 00130 //======================================================================================================================== 00131 void GatewaySupervisor::indicateOtsAlive(const CorePropertySupervisorBase* properties) 00132 { 00133 CorePropertySupervisorBase::indicateOtsAlive(properties); 00134 } 00135 00136 //======================================================================================================================== 00137 void GatewaySupervisor::init(void) 00138 { 00139 supervisorGuiHasBeenLoaded_ = false; 00140 00141 // const XDAQContextTable* contextTable = 00142 // CorePropertySupervisorBase::theConfigurationManager_->__GET_CONFIG__(XDAQContextTable); 00143 // 00144 // CorePropertySupervisorBase::supervisorContextUID_ = 00145 // contextTable->getContextUID( 00146 // getApplicationContext()->getContextDescriptor()->getURL() 00147 // ); 00148 // __COUT__ << "Context UID:" << supervisorContextUID_ << __E__; 00149 // 00150 // CorePropertySupervisorBase::supervisorApplicationUID_ = 00151 // contextTable->getApplicationUID( 00152 // getApplicationContext()->getContextDescriptor()->getURL(), 00153 // getApplicationDescriptor()->getLocalId() 00154 // ); 00155 // 00156 // __COUT__ << "Application UID:" << supervisorApplicationUID_ << __E__; 00157 // 00158 // ConfigurationTree configLinkNode = 00159 // CorePropertySupervisorBase::getSupervisorTreeNode(); 00160 // 00161 // std::string supervisorUID; 00162 // if (!configLinkNode.isDisconnected()) 00163 // supervisorUID = configLinkNode.getValue(); 00164 // else 00165 // supervisorUID = TableViewColumnInfo::DATATYPE_LINK_DEFAULT; 00166 // 00167 //__COUT__ << "GatewaySupervisor UID:" << supervisorUID << __E__; 00168 00169 // setting up thread for UDP thread to drive state machine 00170 bool enableStateChanges = false; 00171 try 00172 { 00173 enableStateChanges = CorePropertySupervisorBase::getSupervisorTableNode() 00174 .getNode("EnableStateChangesOverUDP") 00175 .getValue<bool>(); 00176 } 00177 catch(...) 00178 { 00179 ; 00180 } // ignore errors 00181 00182 try 00183 { 00184 auto artdaqStateChangeEnabled = 00185 CorePropertySupervisorBase::getSupervisorTableNode() 00186 .getNode("EnableARTDAQCommanderPlugin") 00187 .getValue<bool>(); 00188 if(artdaqStateChangeEnabled) 00189 { 00190 auto artdaqStateChangePort = 00191 CorePropertySupervisorBase::getSupervisorTableNode() 00192 .getNode("ARTDAQCommanderID") 00193 .getValue<int>(); 00194 auto artdaqStateChangePluginType = 00195 CorePropertySupervisorBase::getSupervisorTableNode() 00196 .getNode("ARTDAQCommanderType") 00197 .getValue<std::string>(); 00198 theArtdaqCommandable_.init(artdaqStateChangePort, 00199 artdaqStateChangePluginType); 00200 } 00201 } 00202 catch(...) 00203 { 00204 ; 00205 } // ignore errors 00206 00207 if(enableStateChanges) 00208 { 00209 __COUT__ << "Enabling state changes over UDP..." << __E__; 00210 // start state changer UDP listener thread 00211 std::thread( 00212 [](GatewaySupervisor* s) { GatewaySupervisor::StateChangerWorkLoop(s); }, 00213 this) 00214 .detach(); 00215 } 00216 else 00217 __COUT__ << "State changes over UDP are disabled." << __E__; 00218 00219 } // end init() 00220 00221 //======================================================================================================================== 00222 // StateChangerWorkLoop 00223 // child thread 00224 void GatewaySupervisor::StateChangerWorkLoop(GatewaySupervisor* theSupervisor) 00225 { 00226 ConfigurationTree configLinkNode = 00227 theSupervisor->CorePropertySupervisorBase::getSupervisorTableNode(); 00228 00229 std::string ipAddressForStateChangesOverUDP = 00230 configLinkNode.getNode("IPAddressForStateChangesOverUDP").getValue<std::string>(); 00231 int portForStateChangesOverUDP = 00232 configLinkNode.getNode("PortForStateChangesOverUDP").getValue<int>(); 00233 bool acknowledgementEnabled = 00234 configLinkNode.getNode("EnableAckForStateChangesOverUDP").getValue<bool>(); 00235 00236 //__COUT__ << "IPAddressForStateChangesOverUDP = " << ipAddressForStateChangesOverUDP 00237 //<< __E__; 00238 //__COUT__ << "PortForStateChangesOverUDP = " << portForStateChangesOverUDP << 00239 //__E__; 00240 //__COUT__ << "acknowledgmentEnabled = " << acknowledgmentEnabled << __E__; 00241 00242 TransceiverSocket sock(ipAddressForStateChangesOverUDP, 00243 portForStateChangesOverUDP); // Take Port from Table 00244 try 00245 { 00246 sock.initialize(); 00247 } 00248 catch(...) 00249 { 00250 // generate special message to indicate failed socket 00251 __SS__ << "FATAL Console error. Could not initialize socket at ip '" 00252 << ipAddressForStateChangesOverUDP << "' and port " 00253 << portForStateChangesOverUDP 00254 << ". Perhaps it is already in use? Exiting State Changer " 00255 "SOAPUtilities::receive loop." 00256 << __E__; 00257 __COUT__ << ss.str(); 00258 __SS_THROW__; 00259 return; 00260 } 00261 00262 std::size_t commaPosition; 00263 unsigned int commaCounter = 0; 00264 std::size_t begin = 0; 00265 std::string buffer; 00266 std::string errorStr; 00267 std::string fsmName; 00268 std::string command; 00269 std::vector<std::string> parameters; 00270 while(1) 00271 { 00272 // workloop procedure 00273 // if SOAPUtilities::receive a UDP command 00274 // execute command 00275 // else 00276 // sleep 00277 00278 if(sock.receive( 00279 buffer, 0 /*timeoutSeconds*/, 1 /*timeoutUSeconds*/, false /*verbose*/) != 00280 -1) 00281 { 00282 __COUT__ << "UDP State Changer packet received of size = " << buffer.size() 00283 << __E__; 00284 00285 size_t nCommas = std::count(buffer.begin(), buffer.end(), ','); 00286 if(nCommas == 0) 00287 { 00288 __SS__ << "Unrecognized State Machine command :-" << buffer 00289 << "-. Format is FiniteStateMachineName,Command,Parameter(s). " 00290 "Where Parameter(s) is/are optional." 00291 << __E__; 00292 __COUT_INFO__ << ss.str(); 00293 __MOUT_INFO__ << ss.str(); 00294 } 00295 begin = 0; 00296 commaCounter = 0; 00297 parameters.clear(); 00298 while((commaPosition = buffer.find(',', begin)) != std::string::npos || 00299 commaCounter == nCommas) 00300 { 00301 if(commaCounter == nCommas) 00302 commaPosition = buffer.size(); 00303 if(commaCounter == 0) 00304 fsmName = buffer.substr(begin, commaPosition - begin); 00305 else if(commaCounter == 1) 00306 command = buffer.substr(begin, commaPosition - begin); 00307 else 00308 parameters.push_back(buffer.substr(begin, commaPosition - begin)); 00309 __COUT__ << "Word: " << buffer.substr(begin, commaPosition - begin) 00310 << __E__; 00311 00312 begin = commaPosition + 1; 00313 ++commaCounter; 00314 } 00315 00316 // set scope of mutext 00317 { 00318 // should be mutually exclusive with GatewaySupervisor main thread state 00319 // machine accesses lockout the messages array for the remainder of the 00320 // scope this guarantees the reading thread can safely access the 00321 // messages 00322 if(theSupervisor->VERBOSE_MUTEX) 00323 __COUT__ << "Waiting for FSM access" << __E__; 00324 std::lock_guard<std::mutex> lock(theSupervisor->stateMachineAccessMutex_); 00325 if(theSupervisor->VERBOSE_MUTEX) 00326 __COUT__ << "Have FSM access" << __E__; 00327 00328 errorStr = theSupervisor->attemptStateMachineTransition( 00329 0, 00330 0, 00331 command, 00332 fsmName, 00333 WebUsers::DEFAULT_STATECHANGER_USERNAME /*fsmWindowName*/, 00334 WebUsers::DEFAULT_STATECHANGER_USERNAME, 00335 parameters); 00336 } 00337 00338 if(errorStr != "") 00339 { 00340 __SS__ << "UDP State Changer failed to execute command because of the " 00341 "following error: " 00342 << errorStr; 00343 __COUT_ERR__ << ss.str(); 00344 __MOUT_ERR__ << ss.str(); 00345 if(acknowledgementEnabled) 00346 sock.acknowledge(errorStr, true /*verbose*/); 00347 } 00348 else 00349 { 00350 __SS__ << "Successfully executed state change command '" << command 00351 << ".'" << __E__; 00352 __COUT_INFO__ << ss.str(); 00353 __MOUT_INFO__ << ss.str(); 00354 if(acknowledgementEnabled) 00355 sock.acknowledge("Done", true /*verbose*/); 00356 } 00357 } 00358 else 00359 sleep(1); 00360 } 00361 } // end StateChangerWorkLoop 00362 00363 //======================================================================================================================== 00364 // makeSystemLogbookEntry 00365 // makes a logbook entry into all Logbook supervisors 00366 // and specifically the current active experiments within the logbook 00367 // escape entryText to make it html/xml safe!! 00369 void GatewaySupervisor::makeSystemLogbookEntry(std::string entryText) 00370 { 00371 __COUT__ << "Making System Logbook Entry: " << entryText << __E__; 00372 00373 SupervisorInfoMap logbookInfoMap = 00374 allSupervisorInfo_.getAllLogbookTypeSupervisorInfo(); 00375 00376 if(logbookInfoMap.size() == 0) 00377 { 00378 __COUT__ << "No logbooks found! Here is entry: " << entryText << __E__; 00379 __MOUT__ << "No logbooks found! Here is entry: " << entryText << __E__; 00380 return; 00381 } 00382 else 00383 { 00384 __COUT__ << "Making logbook entry: " << entryText << __E__; 00385 __MOUT__ << "Making logbook entry: " << entryText << __E__; 00386 } 00387 00388 //__COUT__ << "before: " << entryText << __E__; 00389 { // input entryText 00390 std::string replace[] = {"\"", "'", "&", "<", ">", "\n", " "}; 00391 std::string with[] = {"%22", "%27", "%26", "%3C", "%3E", "%0A%0D", "%20%20"}; 00392 00393 int numOfKeys = 7; 00394 00395 size_t f; 00396 for(int i = 0; i < numOfKeys; ++i) 00397 { 00398 while((f = entryText.find(replace[i])) != std::string::npos) 00399 { 00400 entryText = entryText.substr(0, f) + with[i] + 00401 entryText.substr(f + replace[i].length()); 00402 //__COUT__ << "found " << " " << entryText << __E__; 00403 } 00404 } 00405 } 00406 //__COUT__ << "after: " << entryText << __E__; 00407 00408 SOAPParameters parameters("EntryText", entryText); 00409 // SOAPParametersV parameters(1); 00410 // parameters[0].setName("EntryText"); parameters[0].setValue(entryText); 00411 00412 for(auto& logbookInfo : logbookInfoMap) 00413 { 00414 xoap::MessageReference retMsg = SOAPMessenger::sendWithSOAPReply( 00415 logbookInfo.second.getDescriptor(), "MakeSystemLogbookEntry", parameters); 00416 00417 SOAPParameters retParameters("Status"); 00418 // SOAPParametersV retParameters(1); 00419 // retParameters[0].setName("Status"); 00420 SOAPUtilities::receive(retMsg, retParameters); 00421 00422 __COUT__ << "Returned Status: " << retParameters.getValue("Status") 00423 << __E__; // retParameters[0].getValue() << __E__ << __E__; 00424 } 00425 } 00426 00427 //======================================================================================================================== 00428 void GatewaySupervisor::Default(xgi::Input* in, xgi::Output* out) 00429 00430 { 00431 // 00432 if(!supervisorGuiHasBeenLoaded_ && 00433 (supervisorGuiHasBeenLoaded_ = 00434 true)) // make system logbook entry that ots has been started 00435 makeSystemLogbookEntry("ots started."); 00436 00437 *out << "<!DOCTYPE HTML><html lang='en'><head><title>ots</title>" << 00438 // show ots icon 00439 // from http://www.favicon-generator.org/ 00440 "<link rel='apple-touch-icon' sizes='57x57' href='/WebPath/images/otsdaqIcons/apple-icon-57x57.png'>\ 00441 <link rel='apple-touch-icon' sizes='60x60' href='/WebPath/images/otsdaqIcons/apple-icon-60x60.png'>\ 00442 <link rel='apple-touch-icon' sizes='72x72' href='/WebPath/images/otsdaqIcons/apple-icon-72x72.png'>\ 00443 <link rel='apple-touch-icon' sizes='76x76' href='/WebPath/images/otsdaqIcons/apple-icon-76x76.png'>\ 00444 <link rel='apple-touch-icon' sizes='114x114' href='/WebPath/images/otsdaqIcons/apple-icon-114x114.png'>\ 00445 <link rel='apple-touch-icon' sizes='120x120' href='/WebPath/images/otsdaqIcons/apple-icon-120x120.png'>\ 00446 <link rel='apple-touch-icon' sizes='144x144' href='/WebPath/images/otsdaqIcons/apple-icon-144x144.png'>\ 00447 <link rel='apple-touch-icon' sizes='152x152' href='/WebPath/images/otsdaqIcons/apple-icon-152x152.png'>\ 00448 <link rel='apple-touch-icon' sizes='180x180' href='/WebPath/images/otsdaqIcons/apple-icon-180x180.png'>\ 00449 <link rel='icon' type='image/png' sizes='192x192' href='/WebPath/images/otsdaqIcons/android-icon-192x192.png'>\ 00450 <link rel='icon' type='image/png' sizes='32x32' href='/WebPath/images/otsdaqIcons/favicon-32x32.png'>\ 00451 <link rel='icon' type='image/png' sizes='96x96' href='/WebPath/images/otsdaqIcons/favicon-96x96.png'>\ 00452 <link rel='icon' type='image/png' sizes='16x16' href='/WebPath/images/otsdaqIcons/favicon-16x16.png'>\ 00453 <link rel='manifest' href='/WebPath/images/otsdaqIcons/manifest.json'>\ 00454 <meta name='msapplication-TileColor' content='#ffffff'>\ 00455 <meta name='msapplication-TileImage' content='/ms-icon-144x144.png'>\ 00456 <meta name='theme-color' content='#ffffff'>" 00457 << 00458 // end show ots icon 00459 "</head>" 00460 << "<frameset col='100%' row='100%'>" 00461 << "<frame src='/WebPath/html/Desktop.html?urn=" 00462 << this->getApplicationDescriptor()->getLocalId() 00463 << "&securityType=" << securityType_ << "'></frameset></html>"; 00464 } 00465 00466 //======================================================================================================================== 00467 void GatewaySupervisor::stateMachineXgiHandler(xgi::Input* in, xgi::Output* out) 00468 { 00469 // for simplicity assume all commands should be mutually exclusive with iterator 00470 // thread state machine accesses (really should just be careful with 00471 // RunControlStateMachine access) 00472 if(VERBOSE_MUTEX) 00473 __COUT__ << "Waiting for FSM access" << __E__; 00474 std::lock_guard<std::mutex> lock(stateMachineAccessMutex_); 00475 if(VERBOSE_MUTEX) 00476 __COUT__ << "Have FSM access" << __E__; 00477 00478 cgicc::Cgicc cgiIn(in); 00479 00480 std::string command = CgiDataUtilities::getData(cgiIn, "StateMachine"); 00481 std::string requestType = 00482 "StateMachine" + command; // prepend StateMachine to request type 00483 00484 HttpXmlDocument xmlOut; 00485 WebUsers::RequestUserInfo userInfo(requestType, 00486 CgiDataUtilities::postData(cgiIn, "CookieCode")); 00487 00488 CorePropertySupervisorBase::getRequestUserInfo(userInfo); 00489 00490 if(!theWebUsers_.xmlRequestOnGateway(cgiIn, out, &xmlOut, userInfo)) 00491 return; // access failed 00492 00493 std::string fsmName = CgiDataUtilities::getData(cgiIn, "fsmName"); 00494 std::string fsmWindowName = CgiDataUtilities::getData(cgiIn, "fsmWindowName"); 00495 fsmWindowName = CgiDataUtilities::decodeURIComponent(fsmWindowName); 00496 std::string currentState = theStateMachine_.getCurrentStateName(); 00497 00498 __COUT__ << "Check for Handled by theIterator_" << __E__; 00499 00500 // check if Iterator should handle 00501 if((activeStateMachineWindowName_ == "" || 00502 activeStateMachineWindowName_ == "iterator") && 00503 theIterator_.handleCommandRequest(xmlOut, command, fsmWindowName)) 00504 { 00505 __COUT__ << "Handled by theIterator_" << __E__; 00506 xmlOut.outputXmlDocument((std::ostringstream*)out, false); 00507 return; 00508 } 00509 00510 // Do not allow transition while in transition 00511 if(theStateMachine_.isInTransition()) 00512 { 00513 __SS__ << "Error - Can not accept request because the State Machine is already " 00514 "in transition!" 00515 << __E__; 00516 __COUT_ERR__ << "\n" << ss.str(); 00517 00518 xmlOut.addTextElementToData("state_tranisition_attempted", 00519 "0"); // indicate to GUI transition NOT attempted 00520 xmlOut.addTextElementToData( 00521 "state_tranisition_attempted_err", 00522 ss.str()); // indicate to GUI transition NOT attempted 00523 xmlOut.outputXmlDocument((std::ostringstream*)out, false, true); 00524 return; 00525 } 00526 00528 // Validate FSM name 00529 // if fsm name != active fsm name 00530 // only allow, if current state is halted or init 00531 // take active fsm name when configured 00532 // else, allow 00533 if(activeStateMachineName_ != "" && activeStateMachineName_ != fsmName) 00534 { 00535 __COUT__ << "currentState = " << currentState << __E__; 00536 if(currentState != "Halted" && currentState != "Initial") 00537 { 00538 // illegal for this FSM name to attempt transition 00539 00540 __SS__ << "Error - Can not accept request because the State Machine " 00541 << "with window name '" << activeStateMachineWindowName_ 00542 << "' (UID: " << activeStateMachineName_ 00543 << ") " 00544 "is currently " 00545 << "in control of State Machine progress. "; 00546 ss << "\n\nIn order for this State Machine with window name '" 00547 << fsmWindowName << "' (UID: " << fsmName 00548 << ") " 00549 "to control progress, please transition to Halted using the active " 00550 << "State Machine '" << activeStateMachineWindowName_ << ".'" << __E__; 00551 __COUT_ERR__ << "\n" << ss.str(); 00552 00553 xmlOut.addTextElementToData("state_tranisition_attempted", 00554 "0"); // indicate to GUI transition NOT attempted 00555 xmlOut.addTextElementToData( 00556 "state_tranisition_attempted_err", 00557 ss.str()); // indicate to GUI transition NOT attempted 00558 xmlOut.outputXmlDocument((std::ostringstream*)out, false, true); 00559 return; 00560 } 00561 else // clear active state machine 00562 { 00563 activeStateMachineName_ = ""; 00564 activeStateMachineWindowName_ = ""; 00565 } 00566 } 00567 00568 // At this point, attempting transition! 00569 00570 std::vector<std::string> parameters; 00571 if(command == "Configure") 00572 parameters.push_back(CgiDataUtilities::postData(cgiIn, "ConfigurationAlias")); 00573 attemptStateMachineTransition( 00574 &xmlOut, out, command, fsmName, fsmWindowName, userInfo.username_, parameters); 00575 } 00576 00577 //======================================================================================================================== 00578 std::string GatewaySupervisor::attemptStateMachineTransition( 00579 HttpXmlDocument* xmldoc, 00580 std::ostringstream* out, 00581 const std::string& command, 00582 const std::string& fsmName, 00583 const std::string& fsmWindowName, 00584 const std::string& username, 00585 const std::vector<std::string>& commandParameters) 00586 { 00587 std::string errorStr = ""; 00588 00589 std::string currentState = theStateMachine_.getCurrentStateName(); 00590 __COUT__ << "State Machine command = " << command << __E__; 00591 __COUT__ << "fsmName = " << fsmName << __E__; 00592 __COUT__ << "fsmWindowName = " << fsmWindowName << __E__; 00593 __COUT__ << "activeStateMachineName_ = " << activeStateMachineName_ << __E__; 00594 __COUT__ << "command = " << command << __E__; 00595 __COUT__ << "commandParameters.size = " << commandParameters.size() << __E__; 00596 00597 SOAPParameters parameters; 00598 if(command == "Configure") 00599 { 00600 if(currentState != "Halted") // check if out of sync command 00601 { 00602 __SS__ << "Error - Can only transition to Configured if the current " 00603 << "state is Halted. Perhaps your state machine is out of sync." 00604 << __E__; 00605 __COUT_ERR__ << "\n" << ss.str(); 00606 errorStr = ss.str(); 00607 00608 if(xmldoc) 00609 xmldoc->addTextElementToData( 00610 "state_tranisition_attempted", 00611 "0"); // indicate to GUI transition NOT attempted 00612 if(xmldoc) 00613 xmldoc->addTextElementToData( 00614 "state_tranisition_attempted_err", 00615 ss.str()); // indicate to GUI transition NOT attempted 00616 if(out) 00617 xmldoc->outputXmlDocument((std::ostringstream*)out, 00618 false /*dispStdOut*/, 00619 true /*allowWhiteSpace*/); 00620 00621 return errorStr; 00622 } 00623 00624 // NOTE Original name of the configuration key 00625 // parameters.addParameter("RUN_KEY",CgiDataUtilities::postData(cgi,"ConfigurationAlias")); 00626 if(commandParameters.size() == 0) 00627 { 00628 __SS__ << "Error - Can only transition to Configured if a Configuration " 00629 "Alias parameter is provided." 00630 << __E__; 00631 __COUT_ERR__ << "\n" << ss.str(); 00632 errorStr = ss.str(); 00633 00634 if(xmldoc) 00635 xmldoc->addTextElementToData( 00636 "state_tranisition_attempted", 00637 "0"); // indicate to GUI transition NOT attempted 00638 if(xmldoc) 00639 xmldoc->addTextElementToData( 00640 "state_tranisition_attempted_err", 00641 ss.str()); // indicate to GUI transition NOT attempted 00642 if(out) 00643 xmldoc->outputXmlDocument((std::ostringstream*)out, 00644 false /*dispStdOut*/, 00645 true /*allowWhiteSpace*/); 00646 00647 return errorStr; 00648 } 00649 00650 parameters.addParameter("ConfigurationAlias", commandParameters[0]); 00651 00652 std::string configurationAlias = parameters.getValue("ConfigurationAlias"); 00653 __COUT__ << "Configure --> Name: ConfigurationAlias Value: " << configurationAlias 00654 << __E__; 00655 00656 // save last used config alias 00657 std::string fn = FSM_LAST_GROUP_ALIAS_PATH + FSM_LAST_GROUP_ALIAS_FILE_START + 00658 username + "." + FSM_USERS_PREFERENCES_FILETYPE; 00659 00660 __COUT__ << "Save FSM preferences: " << fn << __E__; 00661 FILE* fp = fopen(fn.c_str(), "w"); 00662 if(!fp) 00663 { 00664 __SS__ << ("Could not open file: " + fn) << __E__; 00665 __COUT_ERR__ << ss.str(); 00666 __SS_THROW__; 00667 } 00668 fprintf(fp, "FSM_last_configuration_alias %s", configurationAlias.c_str()); 00669 fclose(fp); 00670 00671 activeStateMachineName_ = fsmName; 00672 activeStateMachineWindowName_ = fsmWindowName; 00673 } 00674 else if(command == "Start") 00675 { 00676 if(currentState != "Configured") // check if out of sync command 00677 { 00678 __SS__ 00679 << "Error - Can only transition to Configured if the current " 00680 << "state is Halted. Perhaps your state machine is out of sync. " 00681 << "(Likely the server was restarted or another user changed the state)" 00682 << __E__; 00683 __COUT_ERR__ << "\n" << ss.str(); 00684 errorStr = ss.str(); 00685 00686 if(xmldoc) 00687 xmldoc->addTextElementToData( 00688 "state_tranisition_attempted", 00689 "0"); // indicate to GUI transition NOT attempted 00690 if(xmldoc) 00691 xmldoc->addTextElementToData( 00692 "state_tranisition_attempted_err", 00693 ss.str()); // indicate to GUI transition NOT attempted 00694 if(out) 00695 xmldoc->outputXmlDocument((std::ostringstream*)out, 00696 false /*dispStdOut*/, 00697 true /*allowWhiteSpace*/); 00698 00699 return errorStr; 00700 } 00701 unsigned int runNumber; 00702 if(commandParameters.size() == 0) 00703 { 00704 runNumber = getNextRunNumber(); 00705 setNextRunNumber(runNumber + 1); 00706 } 00707 else 00708 { 00709 runNumber = std::atoi(commandParameters[0].c_str()); 00710 } 00711 parameters.addParameter("RunNumber", runNumber); 00712 } 00713 00714 xoap::MessageReference message = 00715 SOAPUtilities::makeSOAPMessageReference(command, parameters); 00716 // Maybe we return an acknowledgment that the message has been received and processed 00717 xoap::MessageReference reply = stateMachineXoapHandler(message); 00718 // stateMachineWorkLoopManager_.removeProcessedRequests(); 00719 // stateMachineWorkLoopManager_.processRequest(message); 00720 00721 if(xmldoc) 00722 xmldoc->addTextElementToData("state_tranisition_attempted", 00723 "1"); // indicate to GUI transition attempted 00724 if(out) 00725 xmldoc->outputXmlDocument((std::ostringstream*)out, false); 00726 __COUT__ << "FSM state transition launched!" << __E__; 00727 00728 stateMachineLastCommandInput_ = command; 00729 return errorStr; 00730 } // end attemptStateMachineTransition() 00731 00734 // void GatewaySupervisor::stateMachineResultXgiHandler(xgi::Input* in, xgi::Output* out) 00735 // throw (xgi::exception::Exception) 00736 //{ 00737 // cgicc::Cgicc cgiIn(in); 00738 // __COUT__ << "Xgi Request!" << __E__; 00739 // 00740 // uint8_t userPermissions; // uint64_t uid; 00741 // std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode"); 00742 // if (!theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, 00743 // &userPermissions)) 00744 // { 00745 // *out << cookieCode; 00746 // return; 00747 // } 00748 // 00749 // HttpXmlDocument xmldoc(cookieCode); 00750 // 00751 // std::string command = CgiDataUtilities::getData(cgi, "StateMachine"); 00752 // 00753 // SOAPParameters parameters; 00754 // /* 00755 // //FIXME I don't think that there should be this if statement and I guess it has been 00756 // copied from the stateMachineXgiHandler method if (command == "Configure") 00757 // 00758 //{ 00759 // parameters.addParameter("RUN_KEY", CgiDataUtilities::postData(cgi, 00760 //"ConfigurationAlias")); 00761 // __COUT__ << "Configure --> Name: RUN_KEY Value: " << parameters.getValue("RUN_KEY") 00762 //<< __E__; 00763 // } 00764 // else if (command == "Start") 00765 // 00766 //{ 00767 // unsigned int runNumber = getNextRunNumber(); 00768 // std::stringstream runNumberStream; 00769 // runNumberStream << runNumber; 00770 // parameters.addParameter("RUN_NUMBER", runNumberStream.str().c_str()); 00771 // setNextRunNumber(++runNumber); 00772 // } 00773 // */ 00774 // xoap::MessageReference message = SOAPUtilities::makeSOAPMessageReference( 00775 // CgiDataUtilities::getData(cgi, "StateMachine"), parameters); 00776 // //Maybe we return an aknowledgment that the message has been received and processed 00777 // xoap::MessageReference reply = stateMachineResultXoapHandler(message); 00778 // //stateMachineWorkLoopManager_.removeProcessedRequests(); 00779 // //stateMachineWorkLoopManager_.processRequest(message); 00780 // //xmldoc.outputXmlDocument((ostringstream*)out,false); 00781 // __COUT__ << "Done - Xgi Request!" << __E__; 00782 //} 00783 00784 //======================================================================================================================== 00785 xoap::MessageReference GatewaySupervisor::stateMachineXoapHandler( 00786 xoap::MessageReference message) 00787 00788 { 00789 __COUT__ << "Soap Handler!" << __E__; 00790 stateMachineWorkLoopManager_.removeProcessedRequests(); 00791 stateMachineWorkLoopManager_.processRequest(message); 00792 __COUT__ << "Done - Soap Handler!" << __E__; 00793 return message; 00794 } 00795 00796 //======================================================================================================================== 00797 xoap::MessageReference GatewaySupervisor::stateMachineResultXoapHandler( 00798 xoap::MessageReference message) 00799 00800 { 00801 __COUT__ << "Soap Handler!" << __E__; 00802 // stateMachineWorkLoopManager_.removeProcessedRequests(); 00803 // stateMachineWorkLoopManager_.processRequest(message); 00804 __COUT__ << "Done - Soap Handler!" << __E__; 00805 return message; 00806 } 00807 00808 //======================================================================================================================== 00809 bool GatewaySupervisor::stateMachineThread(toolbox::task::WorkLoop* workLoop) 00810 { 00811 stateMachineSemaphore_.take(); 00812 std::string command = 00813 SOAPUtilities::translate(stateMachineWorkLoopManager_.getMessage(workLoop)) 00814 .getCommand(); 00815 00816 __COUT__ << "Propagating command '" << command << "'..." << __E__; 00817 00818 std::string reply = send(allSupervisorInfo_.getGatewayDescriptor(), 00819 stateMachineWorkLoopManager_.getMessage(workLoop)); 00820 stateMachineWorkLoopManager_.report(workLoop, reply, 100, true); 00821 00822 __COUT__ << "Done with command '" << command << ".' Reply = " << reply << __E__; 00823 stateMachineSemaphore_.give(); 00824 00825 if(reply == "Fault") 00826 { 00827 __SS__ << "Failure to send Workloop transition command '" << command 00828 << "!' An error response '" << reply << "' was received." << __E__; 00829 __COUT_ERR__ << ss.str(); 00830 __MOUT_ERR__ << ss.str(); 00831 } 00832 return false; // execute once and automatically remove the workloop so in 00833 // WorkLoopManager the try workLoop->remove(job_) could be commented 00834 // out return true;//go on and then you must do the 00835 // workLoop->remove(job_) in WorkLoopManager 00836 } 00837 00838 //======================================================================================================================== 00839 // infoRequestHandler ~~ 00840 // Call from JS GUI 00841 // parameter: 00842 // 00843 void GatewaySupervisor::infoRequestHandler(xgi::Input* in, xgi::Output* out) 00844 00845 { 00846 __COUT__ << "Starting to Request!" << __E__; 00847 00848 cgicc::Cgicc cgiIn(in); 00849 std::string requestType = 00850 "infoRequestHandler"; // force request type to infoRequestHandler 00851 00852 HttpXmlDocument xmlOut; 00853 WebUsers::RequestUserInfo userInfo(requestType, 00854 CgiDataUtilities::postData(cgiIn, "CookieCode")); 00855 00856 CorePropertySupervisorBase::getRequestUserInfo(userInfo); 00857 00858 if(!theWebUsers_.xmlRequestOnGateway(cgiIn, out, &xmlOut, userInfo)) 00859 return; // access failed 00860 00861 // If the thread is canceled when you are still in this method that activated it, then 00862 // everything will freeze. The way the workloop manager now works is safe since it 00863 // cancel the thread only when the infoRequestResultHandler is called and that method 00864 // can be called ONLY when I am already out of here! 00865 00866 HttpXmlDocument tmpDoc = infoRequestWorkLoopManager_.processRequest(cgiIn); 00867 00868 xmlOut.copyDataChildren(tmpDoc); 00869 00870 xmlOut.outputXmlDocument((std::ostringstream*)out, false); 00871 } 00872 00873 //======================================================================================================================== 00874 void GatewaySupervisor::infoRequestResultHandler(xgi::Input* in, xgi::Output* out) 00875 00876 { 00877 __COUT__ << "Starting ask!" << __E__; 00878 cgicc::Cgicc cgi(in); 00879 00880 cgicc::Cgicc cgiIn(in); 00881 std::string requestType = 00882 "infoRequestResultHandler"; // force request type to infoRequestResultHandler 00883 00884 HttpXmlDocument xmlOut; 00885 WebUsers::RequestUserInfo userInfo(requestType, 00886 CgiDataUtilities::postData(cgiIn, "CookieCode")); 00887 00888 CorePropertySupervisorBase::getRequestUserInfo(userInfo); 00889 00890 if(!theWebUsers_.xmlRequestOnGateway(cgiIn, out, &xmlOut, userInfo)) 00891 return; // access failed 00892 00893 // //**** start LOGIN GATEWAY CODE ***// 00894 // //If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers 00895 // optionally for uint8_t userPermissions, uint64_t uid 00896 // //Else, error message is returned in cookieCode 00897 // std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode"); 00898 // uint8_t userPermissions;// uint64_t uid; 00899 // if (!theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, &userPermissions)) 00900 // { 00901 // *out << cookieCode; 00902 // return; 00903 // } 00904 // //**** end LOGIN GATEWAY CODE ***// 00905 // 00906 // HttpXmlDocument xmldoc(cookieCode); 00907 00908 infoRequestWorkLoopManager_.getRequestResult(cgiIn, xmlOut); 00909 00910 // return xml doc holding server response 00911 xmlOut.outputXmlDocument((std::ostringstream*)out, false); 00912 00913 __COUT__ << "Done asking!" << __E__; 00914 } 00915 00916 //======================================================================================================================== 00917 bool GatewaySupervisor::infoRequestThread(toolbox::task::WorkLoop* workLoop) 00918 { 00919 // std::string workLoopName = workLoop->getName(); 00920 // __COUT__ << " Starting WorkLoop: " << workLoopName << __E__; 00921 // __COUT__ << " Ready to lock" << __E__; 00922 infoRequestSemaphore_.take(); 00923 // __COUT__ << " Locked" << __E__; 00924 vectorTest_.clear(); 00925 00926 for(unsigned long long i = 0; i < 100000000; i++) 00927 { 00928 counterTest_ += 2; 00929 vectorTest_.push_back(counterTest_); 00930 } 00931 00932 infoRequestWorkLoopManager_.report( 00933 workLoop, "RESULT: This is the best result ever", 50, false); 00934 std::string workLoopName = workLoop->getName(); 00935 __COUT__ << workLoopName << " test: " << counterTest_ 00936 << " vector size: " << vectorTest_.size() << __E__; 00937 wait(400, "InfoRequestThread ----- locked"); 00938 infoRequestSemaphore_.give(); 00939 // __COUT__ << " Lock released" << __E__; 00940 wait(200, "InfoRequestThread"); 00941 // __COUT__ << " Ready to lock again" << __E__; 00942 infoRequestSemaphore_.take(); 00943 // __COUT__ << " Locked again" << __E__; 00944 vectorTest_.clear(); 00945 00946 for(unsigned long long i = 0; i < 100000000; i++) 00947 { 00948 counterTest_ += 2; 00949 vectorTest_.push_back(counterTest_); 00950 } 00951 00952 wait(400, "InfoRequestThread ----- locked"); 00953 __COUT__ << workLoopName << " test: " << counterTest_ 00954 << " vector size: " << vectorTest_.size() << __E__; 00955 infoRequestSemaphore_.give(); 00956 // __COUT__ << " Lock released again" << __E__; 00957 // infoRequestWorkLoopManager_->report(workLoop,"RESULT: This is the best result 00958 // ever"); 00959 infoRequestWorkLoopManager_.report( 00960 workLoop, theStateMachine_.getCurrentStateName(), 100, true); 00961 // __COUT__ << " Done with WorkLoop: " << workLoopName << __E__; 00962 return false; // execute once and automatically remove the workloop so in 00963 // WorkLoopManager the try workLoop->remove(job_) could be commented 00964 // out return true;//go on and then you must do the 00965 // workLoop->remove(job_) in WorkLoopManager 00966 } 00967 00968 //======================================================================================================================== 00969 void GatewaySupervisor::stateInitial(toolbox::fsm::FiniteStateMachine& fsm) 00970 00971 { 00972 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 00973 // diagService_->reportError("--- GatewaySupervisor is in its Initial state 00974 // ---",DIAGINFO); diagService_->reportError("GatewaySupervisor::stateInitial: 00975 // workloop active: "+stringF(calibWorkloop_->isActive())+", workloop type: 00976 // "+calibWorkloop_->getType(),DIAGINFO); 00977 } 00978 00979 //======================================================================================================================== 00980 void GatewaySupervisor::statePaused(toolbox::fsm::FiniteStateMachine& fsm) 00981 00982 { 00983 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 00984 /* 00985 try 00986 { 00987 rcmsStateNotifier_.stateChanged("Paused", ""); 00988 } 00989 catch(xcept::Exception &e) 00990 { 00991 diagService_->reportError("Failed to notify state change : "+ 00992 xcept::stdformat_exception_history(e),DIAGERROR); 00993 } 00994 00995 diagService_->reportError("GatewaySupervisor::statePaused: workloop active: 00996 "+stringF(calibWorkloop_->isActive())+", workloop type: 00997 "+calibWorkloop_->getType(),DIAGINFO); 00998 */ 00999 } 01000 01001 //======================================================================================================================== 01002 void GatewaySupervisor::stateRunning(toolbox::fsm::FiniteStateMachine& fsm) 01003 01004 { 01005 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01006 /* 01007 try 01008 { 01009 rcmsStateNotifier_.stateChanged("Running", ""); 01010 } 01011 catch(xcept::Exception &e) 01012 { 01013 diagService_->reportError("Failed to notify state change : "+ 01014 xcept::stdformat_exception_history(e),DIAGERROR); 01015 } 01016 01017 diagService_->reportError("GatewaySupervisor::stateRunning: workloop active: 01018 "+stringF(calibWorkloop_->isActive())+", workloop type: 01019 "+calibWorkloop_->getType(),DIAGINFO); 01020 */ 01021 } 01022 01023 //======================================================================================================================== 01024 void GatewaySupervisor::stateHalted(toolbox::fsm::FiniteStateMachine& fsm) 01025 01026 { 01027 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01028 __COUT__ << "Fsm is in transition? " 01029 << (theStateMachine_.isInTransition() ? "yes" : "no") << __E__; 01030 01031 /* 01032 percentageConfigured_=0.0; 01033 aliasesAndKeys_=PixelConfigInterface::getAliases(); 01034 diagService_->reportError("GatewaySupervisor::stateHalted: aliases and keys 01035 reloaded",DIAGINFO); previousState_ = theStateMachine_.getCurrentStateName(); 01036 diagService_->reportError("GatewaySupervisor::stateHalted: workloop active: 01037 "+stringF(calibWorkloop_->isActive())+", workloop type: 01038 "+calibWorkloop_->getType(),DIAGINFO); 01039 01040 //(hopefully) make RCMS aware of successful Recovery 01041 //need to test that: (a) this works and (b) this does not break anything (regular 01042 Halt transition) 01043 //update -- condition (b) seems to be satisfied. not yet sure about condition (a) 01044 try 01045 { 01046 rcmsStateNotifier_.stateChanged("Halted", ""); 01047 } 01048 catch(xcept::Exception &e) 01049 01050 { 01051 diagService_->reportError("Failed to notify state change : "+ 01052 xcept::stdformat_exception_history(e),DIAGERROR); 01053 } 01054 */ 01055 } 01056 01057 //======================================================================================================================== 01058 void GatewaySupervisor::stateConfigured(toolbox::fsm::FiniteStateMachine& fsm) 01059 01060 { 01061 /* 01062 // Notify RCMS of having entered the Configured state 01063 try 01064 01065 { 01066 //rcmsStateNotifier_.stateChanged(previousState_.toString(), ""); 01067 rcmsStateNotifier_.stateChanged("Configured", std::stringF(theGlobalKey_->key()) ); 01068 } 01069 catch(xcept::Exception &e) 01070 01071 { 01072 diagService_->reportError("Failed to notify state change : "+ 01073 xcept::stdformat_exception_history(e),DIAGERROR); 01074 } 01075 01076 PixelTimer debugTimer; 01077 if (extratimers_) 01078 { 01079 debugTimer.setName("GatewaySupervisor::stateConfigured"); 01080 debugTimer.printTime("RCMS notified of Configured state"); 01081 } 01082 if (configurationTimer_.started() ) 01083 { 01084 configurationTimer_.stop(); 01085 01086 std::string confsource(getenv("PIXELCONFIGURATIONBASE")); 01087 if (confsource != "DB") confsource = "files"; 01088 01089 diagService_->reportError("Total configuration time ["+confsource+"] = 01090 "+stringF(configurationTimer_.tottime()),DIAGUSERINFO); configurationTimer_.reset(); 01091 } 01092 01093 diagService_->reportError( "GatewaySupervisor::stateConfigured: workloop active: 01094 "+stringF(calibWorkloop_->isActive())+", workloop type: 01095 "+calibWorkloop_->getType(),DIAGDEBUG); 01096 */ 01097 } 01098 01099 // void GatewaySupervisor::stateTTSTestMode (toolbox::fsm::FiniteStateMachine & fsm) 01100 //{ 01101 // previousState_ = theStateMachine_.getCurrentStateName(); 01102 //} 01103 01104 // void GatewaySupervisor::inError (toolbox::fsm::FiniteStateMachine & fsm) 01105 //{ 01106 // previousState_ = theStateMachine_.getCurrentStateName(); 01107 // rcmsStateNotifier_.stateChanged("Error", ""); 01108 //} 01109 01110 /* 01111 xoap::MessageReference GatewaySupervisor::reset (xoap::MessageReference message) 01112 01113 { 01114 //diagService_->reportError("New state before reset is: " + 01115 theStateMachine_.getCurrentStateName(),DIAGINFO); 01116 01117 theStateMachine_.reset(); 01118 01119 xoap::MessageReference reply = xoap::createMessage(); 01120 xoap::SOAPEnvelope envelope = reply->getSOAPPart().getEnvelope(); 01121 xoap::SOAPName responseName = envelope.createName("ResetResponse", "xdaq", XDAQ_NS_URI); 01122 (void) envelope.getBody().addBodyElement ( responseName ); 01123 01124 diagService_->reportError("New state after reset is: " + 01125 theStateMachine_.getCurrentStateName(),DIAGINFO); 01126 01127 return reply; 01128 } 01129 */ 01130 01131 //======================================================================================================================== 01132 void GatewaySupervisor::inError(toolbox::fsm::FiniteStateMachine& fsm) 01133 01134 { 01135 __COUT__ 01136 << "Fsm current state: " 01137 << "Failed" 01138 // theStateMachine_.getCurrentStateName() //There may be a race condition here 01139 // when async errors occur (e.g. immediately in running) 01140 << __E__; 01141 // rcmsStateNotifier_.stateChanged("Error", ""); 01142 } 01143 01144 //======================================================================================================================== 01145 void GatewaySupervisor::enteringError(toolbox::Event::Reference e) 01146 { 01147 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01148 01149 // extract error message and save for user interface access 01150 toolbox::fsm::FailedEvent& failedEvent = dynamic_cast<toolbox::fsm::FailedEvent&>(*e); 01151 01152 __SS__; 01153 01154 // handle async error message differently 01155 if(RunControlStateMachine::asyncFailureReceived_) 01156 { 01157 ss << "\nAn asynchronous failure was encountered." 01158 << ".\n\nException:\n" 01159 << failedEvent.getException().what() << __E__; 01160 RunControlStateMachine::asyncFailureReceived_ = false; // clear async error 01161 } 01162 else 01163 { 01164 ss << "\nFailure performing transition from " << failedEvent.getFromState() << "-" 01165 << theStateMachine_.getStateName(failedEvent.getFromState()) << " to " 01166 << failedEvent.getToState() << "-" 01167 << theStateMachine_.getStateName(failedEvent.getToState()) 01168 << ".\n\nException:\n" 01169 << failedEvent.getException().what() << __E__; 01170 } 01171 01172 __COUT_ERR__ << "\n" << ss.str(); 01173 theStateMachine_.setErrorMessage(ss.str()); 01174 01175 // move everything else to Error! 01176 broadcastMessage(SOAPUtilities::makeSOAPMessageReference("Error")); 01177 } 01178 01179 //======================================================================================================================== 01180 void GatewaySupervisor::checkForAsyncError() 01181 { 01182 if(RunControlStateMachine::asyncFailureReceived_) 01183 { 01184 __COUTV__(RunControlStateMachine::asyncFailureReceived_); 01185 01186 XCEPT_RAISE(toolbox::fsm::exception::Exception, 01187 RunControlStateMachine::getErrorMessage()); 01188 return; 01189 } 01190 } // end checkForAsyncError() 01191 01195 01196 //======================================================================================================================== 01197 void GatewaySupervisor::transitionConfiguring(toolbox::Event::Reference e) 01198 { 01199 checkForAsyncError(); 01200 01201 RunControlStateMachine::theProgressBar_.step(); 01202 01203 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01204 01205 std::string systemAlias = 01206 SOAPUtilities::translate(theStateMachine_.getCurrentMessage()) 01207 .getParameters() 01208 .getValue("ConfigurationAlias"); 01209 01210 __COUT__ << "Transition parameter: " << systemAlias << __E__; 01211 01212 RunControlStateMachine::theProgressBar_.step(); 01213 01214 try 01215 { 01216 CorePropertySupervisorBase::theConfigurationManager_ 01217 ->init(); // completely reset to re-align with any changes 01218 } 01219 catch(...) 01220 { 01221 __SS__ << "\nTransition to Configuring interrupted! " 01222 << "The Configuration Manager could not be initialized." << __E__; 01223 01224 __COUT_ERR__ << "\n" << ss.str(); 01225 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01226 return; 01227 } 01228 01229 RunControlStateMachine::theProgressBar_.step(); 01230 01231 // Translate the system alias to a group name/key 01232 try 01233 { 01234 theConfigurationTableGroup_ = 01235 CorePropertySupervisorBase::theConfigurationManager_->getTableGroupFromAlias( 01236 systemAlias); 01237 } 01238 catch(...) 01239 { 01240 __COUT_INFO__ << "Exception occurred" << __E__; 01241 } 01242 01243 RunControlStateMachine::theProgressBar_.step(); 01244 01245 if(theConfigurationTableGroup_.second.isInvalid()) 01246 { 01247 __SS__ << "\nTransition to Configuring interrupted! System Alias " << systemAlias 01248 << " could not be translated to a group name and key." << __E__; 01249 01250 __COUT_ERR__ << "\n" << ss.str(); 01251 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01252 return; 01253 } 01254 01255 RunControlStateMachine::theProgressBar_.step(); 01256 01257 __COUT__ << "Configuration table group name: " << theConfigurationTableGroup_.first 01258 << " key: " << theConfigurationTableGroup_.second << __E__; 01259 01260 // make logbook entry 01261 { 01262 std::stringstream ss; 01263 ss << "Configuring '" << systemAlias << "' which translates to " 01264 << theConfigurationTableGroup_.first << " (" 01265 << theConfigurationTableGroup_.second << ")."; 01266 makeSystemLogbookEntry(ss.str()); 01267 } 01268 01269 RunControlStateMachine::theProgressBar_.step(); 01270 01271 // load and activate 01272 try 01273 { 01274 CorePropertySupervisorBase::theConfigurationManager_->loadTableGroup( 01275 theConfigurationTableGroup_.first, theConfigurationTableGroup_.second, true); 01276 01277 // When configured, set the translated System Alias to be persistently active 01278 ConfigurationManagerRW tmpCfgMgr("TheSupervisor"); 01279 tmpCfgMgr.activateTableGroup(theConfigurationTableGroup_.first, 01280 theConfigurationTableGroup_.second); 01281 } 01282 catch(...) 01283 { 01284 __SS__ << "\nTransition to Configuring interrupted! System Alias " << systemAlias 01285 << " was translated to " << theConfigurationTableGroup_.first << " (" 01286 << theConfigurationTableGroup_.second 01287 << ") but could not be loaded and initialized." << __E__; 01288 ss << "\n\nTo debug this problem, try activating this group in the Configuration " 01289 "GUI " 01290 << " and detailed errors will be shown." << __E__; 01291 __COUT_ERR__ << "\n" << ss.str(); 01292 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01293 return; 01294 } 01295 01296 // check if configuration dump is enabled on configure transition 01297 { 01298 ConfigurationTree configLinkNode = 01299 CorePropertySupervisorBase::theConfigurationManager_->getSupervisorTableNode( 01300 supervisorContextUID_, supervisorApplicationUID_); 01301 if(!configLinkNode.isDisconnected()) 01302 { 01303 try // errors in dump are not tolerated 01304 { 01305 bool dumpConfiguration = true; 01306 std::string dumpFilePath, dumpFileRadix, dumpFormat; 01307 try // for backwards compatibility 01308 { 01309 ConfigurationTree fsmLinkNode = 01310 configLinkNode.getNode("LinkToStateMachineTable") 01311 .getNode(activeStateMachineName_); 01312 dumpConfiguration = 01313 fsmLinkNode 01314 .getNode("EnableConfigurationDumpOnConfigureTransition") 01315 .getValue<bool>(); 01316 dumpFilePath = 01317 fsmLinkNode.getNode("ConfigurationDumpOnConfigureFilePath") 01318 .getValue<std::string>(); 01319 dumpFileRadix = 01320 fsmLinkNode.getNode("ConfigurationDumpOnConfigureFileRadix") 01321 .getValue<std::string>(); 01322 dumpFormat = fsmLinkNode.getNode("ConfigurationDumpOnConfigureFormat") 01323 .getValue<std::string>(); 01324 } 01325 catch(std::runtime_error& e) 01326 { 01327 __COUT_INFO__ << "FSM configuration dump Link disconnected." << __E__; 01328 dumpConfiguration = false; 01329 } 01330 01331 if(dumpConfiguration) 01332 { 01333 // dump configuration 01334 CorePropertySupervisorBase::theConfigurationManager_ 01335 ->dumpActiveConfiguration(dumpFilePath + "/" + dumpFileRadix + 01336 "_" + std::to_string(time(0)) + 01337 ".dump", 01338 dumpFormat); 01339 } 01340 } 01341 catch(std::runtime_error& e) 01342 { 01343 __SS__ << "\nTransition to Configuring interrupted! There was an error " 01344 "identified " 01345 << "during the configuration dump attempt:\n\n " << e.what() 01346 << __E__; 01347 __COUT_ERR__ << "\n" << ss.str(); 01348 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01349 return; 01350 } 01351 catch(...) 01352 { 01353 __SS__ << "\nTransition to Configuring interrupted! There was an error " 01354 "identified " 01355 << "during the configuration dump attempt.\n\n " << __E__; 01356 __COUT_ERR__ << "\n" << ss.str(); 01357 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01358 return; 01359 } 01360 } 01361 } 01362 01363 RunControlStateMachine::theProgressBar_.step(); 01364 SOAPParameters parameters; 01365 parameters.addParameter("ConfigurationTableGroupName", 01366 theConfigurationTableGroup_.first); 01367 parameters.addParameter("ConfigurationTableGroupKey", 01368 theConfigurationTableGroup_.second.toString()); 01369 01370 // update Macro Maker front end list 01371 { 01372 __COUT__ << "Initializing Macro Maker." << __E__; 01373 xoap::MessageReference message = 01374 SOAPUtilities::makeSOAPMessageReference("FECommunication"); 01375 01376 SOAPParameters parameters; 01377 parameters.addParameter("type", "initFElist"); 01378 parameters.addParameter("groupName", theConfigurationTableGroup_.first); 01379 parameters.addParameter("groupKey", 01380 theConfigurationTableGroup_.second.toString()); 01381 SOAPUtilities::addParameters(message, parameters); 01382 01383 __COUT__ << "Sending FE communication: " << SOAPUtilities::translate(message) 01384 << __E__; 01385 01386 std::string reply = 01387 SOAPMessenger::send(CorePropertySupervisorBase::allSupervisorInfo_ 01388 .getAllMacroMakerTypeSupervisorInfo() 01389 .begin() 01390 ->second.getDescriptor(), 01391 message); 01392 01393 __COUT__ << "Macro Maker init reply: " << reply << __E__; 01394 if(reply == "Error") 01395 { 01396 __SS__ << "\nTransition to Configuring interrupted! There was an error " 01397 "identified initializing Macro Maker.\n\n " 01398 << __E__; 01399 __COUT_ERR__ << "\n" << ss.str(); 01400 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01401 return; 01402 } 01403 } 01404 01405 // xoap::MessageReference message = 01406 // SOAPUtilities::makeSOAPMessageReference(SOAPUtilities::translate(theStateMachine_.getCurrentMessage()).getCommand(), 01407 // parameters); 01408 xoap::MessageReference message = theStateMachine_.getCurrentMessage(); 01409 SOAPUtilities::addParameters(message, parameters); 01410 broadcastMessage(message); 01411 RunControlStateMachine::theProgressBar_.step(); 01412 // Advertise the exiting of this method 01413 // diagService_->reportError("GatewaySupervisor::stateConfiguring: Exiting",DIAGINFO); 01414 01415 // save last configured group name/key 01416 saveGroupNameAndKey(theConfigurationTableGroup_, 01417 FSM_LAST_CONFIGURED_GROUP_ALIAS_FILE); 01418 01419 __COUT__ << "Done configuring." << __E__; 01420 RunControlStateMachine::theProgressBar_.complete(); 01421 } // end transitionConfiguring() 01422 01423 //======================================================================================================================== 01424 void GatewaySupervisor::transitionHalting(toolbox::Event::Reference e) 01425 { 01426 checkForAsyncError(); 01427 01428 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01429 01430 makeSystemLogbookEntry("Run halting."); 01431 01432 broadcastMessage(theStateMachine_.getCurrentMessage()); 01433 } // end transitionHalting() 01434 01435 //======================================================================================================================== 01436 void GatewaySupervisor::transitionShuttingDown(toolbox::Event::Reference e) 01437 01438 { 01439 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01440 01441 RunControlStateMachine::theProgressBar_.step(); 01442 makeSystemLogbookEntry("System shutting down."); 01443 RunControlStateMachine::theProgressBar_.step(); 01444 01445 // kill all non-gateway contexts 01446 GatewaySupervisor::launchStartOTSCommand( 01447 "OTS_APP_SHUTDOWN", CorePropertySupervisorBase::theConfigurationManager_); 01448 RunControlStateMachine::theProgressBar_.step(); 01449 01450 // important to give time for StartOTS script to recognize command (before user does 01451 // Startup again) 01452 for(int i = 0; i < 5; ++i) 01453 { 01454 sleep(1); 01455 RunControlStateMachine::theProgressBar_.step(); 01456 } 01457 } 01458 01459 //======================================================================================================================== 01460 void GatewaySupervisor::transitionStartingUp(toolbox::Event::Reference e) 01461 01462 { 01463 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01464 01465 RunControlStateMachine::theProgressBar_.step(); 01466 makeSystemLogbookEntry("System starting up."); 01467 RunControlStateMachine::theProgressBar_.step(); 01468 01469 // start all non-gateway contexts 01470 GatewaySupervisor::launchStartOTSCommand( 01471 "OTS_APP_STARTUP", CorePropertySupervisorBase::theConfigurationManager_); 01472 RunControlStateMachine::theProgressBar_.step(); 01473 01474 // important to give time for StartOTS script to recognize command and for apps to 01475 // instantiate things (before user does Initialize) 01476 for(int i = 0; i < 10; ++i) 01477 { 01478 sleep(1); 01479 RunControlStateMachine::theProgressBar_.step(); 01480 } 01481 } 01482 01483 //======================================================================================================================== 01484 void GatewaySupervisor::transitionInitializing(toolbox::Event::Reference e) 01485 01486 { 01487 __COUT__ << theStateMachine_.getCurrentStateName() << __E__; 01488 01489 broadcastMessage(theStateMachine_.getCurrentMessage()); 01490 01491 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01492 __COUT__ << "Fsm current transition: " 01493 << theStateMachine_.getCurrentTransitionName(e->type()) << __E__; 01494 __COUT__ << "Fsm final state: " 01495 << theStateMachine_.getTransitionFinalStateName(e->type()) << __E__; 01496 } 01497 01498 //======================================================================================================================== 01499 void GatewaySupervisor::transitionPausing(toolbox::Event::Reference e) 01500 { 01501 checkForAsyncError(); 01502 01503 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01504 01505 makeSystemLogbookEntry("Run pausing."); 01506 01507 // the current message is not for Pause if its due to async failure 01508 if(RunControlStateMachine::asyncSoftFailureReceived_) 01509 { 01510 __COUT_ERR__ << "Broadcasting pause for async SOFT error!" << __E__; 01511 broadcastMessage(SOAPUtilities::makeSOAPMessageReference("Pause")); 01512 } 01513 else 01514 broadcastMessage(theStateMachine_.getCurrentMessage()); 01515 } 01516 01517 //======================================================================================================================== 01518 void GatewaySupervisor::transitionResuming(toolbox::Event::Reference e) 01519 { 01520 if(RunControlStateMachine::asyncSoftFailureReceived_) 01521 { 01522 // clear async soft error 01523 __COUT_INFO__ << "Clearing async SOFT error!" << __E__; 01524 RunControlStateMachine::asyncSoftFailureReceived_ = false; 01525 } 01526 01527 checkForAsyncError(); 01528 01529 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01530 01531 makeSystemLogbookEntry("Run resuming."); 01532 01533 broadcastMessage(theStateMachine_.getCurrentMessage()); 01534 } // end transitionResuming() 01535 01536 //======================================================================================================================== 01537 void GatewaySupervisor::transitionStarting(toolbox::Event::Reference e) 01538 { 01539 if(RunControlStateMachine::asyncSoftFailureReceived_) 01540 { 01541 // clear async soft error 01542 __COUT_INFO__ << "Clearing async SOFT error!" << __E__; 01543 RunControlStateMachine::asyncSoftFailureReceived_ = false; 01544 } 01545 01546 checkForAsyncError(); 01547 01548 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01549 01550 SOAPParameters parameters("RunNumber"); 01551 SOAPUtilities::receive(theStateMachine_.getCurrentMessage(), parameters); 01552 01553 std::string runNumber = parameters.getValue("RunNumber"); 01554 __COUTV__(runNumber); 01555 01556 // check if configuration dump is enabled on configure transition 01557 { 01558 ConfigurationTree configLinkNode = 01559 CorePropertySupervisorBase::theConfigurationManager_->getSupervisorTableNode( 01560 supervisorContextUID_, supervisorApplicationUID_); 01561 if(!configLinkNode.isDisconnected()) 01562 { 01563 try // errors in dump are not tolerated 01564 { 01565 bool dumpConfiguration = true; 01566 std::string dumpFilePath, dumpFileRadix, dumpFormat; 01567 try // for backwards compatibility 01568 { 01569 ConfigurationTree fsmLinkNode = 01570 configLinkNode.getNode("LinkToStateMachineTable") 01571 .getNode(activeStateMachineName_); 01572 dumpConfiguration = 01573 fsmLinkNode.getNode("EnableConfigurationDumpOnRunTransition") 01574 .getValue<bool>(); 01575 dumpFilePath = fsmLinkNode.getNode("ConfigurationDumpOnRunFilePath") 01576 .getValue<std::string>(); 01577 dumpFileRadix = fsmLinkNode.getNode("ConfigurationDumpOnRunFileRadix") 01578 .getValue<std::string>(); 01579 dumpFormat = fsmLinkNode.getNode("ConfigurationDumpOnRunFormat") 01580 .getValue<std::string>(); 01581 } 01582 catch(std::runtime_error& e) 01583 { 01584 __COUT_INFO__ << "FSM configuration dump Link disconnected." << __E__; 01585 dumpConfiguration = false; 01586 } 01587 01588 if(dumpConfiguration) 01589 { 01590 // dump configuration 01591 CorePropertySupervisorBase::theConfigurationManager_ 01592 ->dumpActiveConfiguration(dumpFilePath + "/" + dumpFileRadix + 01593 "_Run" + runNumber + "_" + 01594 std::to_string(time(0)) + ".dump", 01595 dumpFormat); 01596 } 01597 } 01598 catch(std::runtime_error& e) 01599 { 01600 __SS__ << "\nTransition to Running interrupted! There was an error " 01601 "identified " 01602 << "during the configuration dump attempt:\n\n " << e.what() 01603 << __E__; 01604 __COUT_ERR__ << "\n" << ss.str(); 01605 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01606 return; 01607 } 01608 catch(...) 01609 { 01610 __SS__ << "\nTransition to Running interrupted! There was an error " 01611 "identified " 01612 << "during the configuration dump attempt.\n\n " << __E__; 01613 __COUT_ERR__ << "\n" << ss.str(); 01614 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01615 return; 01616 } 01617 } 01618 } 01619 01620 makeSystemLogbookEntry("Run " + runNumber + " starting."); 01621 01622 broadcastMessage(theStateMachine_.getCurrentMessage()); 01623 01624 // save last started group name/key 01625 saveGroupNameAndKey(theConfigurationTableGroup_, FSM_LAST_STARTED_GROUP_ALIAS_FILE); 01626 } 01627 01628 //======================================================================================================================== 01629 void GatewaySupervisor::transitionStopping(toolbox::Event::Reference e) 01630 { 01631 checkForAsyncError(); 01632 01633 __COUT__ << "Fsm current state: " << theStateMachine_.getCurrentStateName() << __E__; 01634 01635 makeSystemLogbookEntry("Run stopping."); 01636 01637 broadcastMessage(theStateMachine_.getCurrentMessage()); 01638 } 01639 01643 01644 //======================================================================================================================== 01645 // handleBroadcastMessageTarget 01646 // Sends message and gets reply 01647 // Handles sub-iterations at same target 01648 // if failure, THROW state machine exception 01649 // returns true if iterations are done, else false 01650 bool GatewaySupervisor::handleBroadcastMessageTarget(const SupervisorInfo& appInfo, 01651 xoap::MessageReference message, 01652 const std::string& command, 01653 const unsigned int& iteration, 01654 std::string& reply, 01655 unsigned int threadIndex) 01656 { 01657 unsigned int subIteration = 0; // reset for next subIteration loop 01658 bool subIterationsDone = false; 01659 bool iterationsDone = true; 01660 01661 while(!subIterationsDone) // start subIteration handling loop 01662 { 01663 subIterationsDone = true; 01664 RunControlStateMachine::theProgressBar_.step(); 01665 01666 // add subIteration index to message 01667 if(subIteration) 01668 { 01669 SOAPParameters parameters; 01670 parameters.addParameter("subIterationIndex", subIteration); 01671 SOAPUtilities::addParameters(message, parameters); 01672 } 01673 01674 if(iteration || subIteration) 01675 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01676 << "Adding iteration parameters " << iteration << "." << subIteration 01677 << __E__; 01678 01679 RunControlStateMachine::theProgressBar_.step(); 01680 01681 if(iteration == 0 && subIteration == 0) 01682 { 01683 for(unsigned int j = 0; j < 4; ++j) 01684 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01685 << "Sending message to Supervisor " << appInfo.getName() 01686 << " [LID=" << appInfo.getId() << "]: " << command << __E__; 01687 } 01688 else // else this not the first time through the supervisors 01689 { 01690 if(subIteration == 0) 01691 { 01692 for(unsigned int j = 0; j < 4; ++j) 01693 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01694 << "Sending message to Supervisor " << appInfo.getName() 01695 << " [LID=" << appInfo.getId() << "]: " << command 01696 << " (iteration: " << iteration << ")" << __E__; 01697 } 01698 else 01699 { 01700 for(unsigned int j = 0; j < 4; ++j) 01701 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01702 << "Sending message to Supervisor " << appInfo.getName() 01703 << " [LID=" << appInfo.getId() << "]: " << command 01704 << " (iteration: " << iteration 01705 << ", sub-iteration: " << subIteration << ")" << __E__; 01706 } 01707 } 01708 01709 { 01710 // add the message index 01711 SOAPParameters parameters; 01712 { // mutex scope 01713 std::lock_guard<std::mutex> lock(broadcastCommandMessageIndexMutex_); 01714 parameters.addParameter("commandId", broadcastCommandMessageIndex_++); 01715 } // end mutex scope 01716 SOAPUtilities::addParameters(message, parameters); 01717 } 01718 01719 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01720 << "Sending... \t" << SOAPUtilities::translate(message) << std::endl; 01721 01722 try // attempt transmit of transition command 01723 { 01724 reply = send(appInfo.getDescriptor(), message); 01725 } 01726 catch(const xdaq::exception::Exception& e) // due to xoap send failure 01727 { 01728 // do not kill whole system if xdaq xoap failure 01729 __SS__ << "Error! Gateway Supervisor can NOT " << command 01730 << " Supervisor instance = '" << appInfo.getName() 01731 << "' [LID=" << appInfo.getId() << "] in Context '" 01732 << appInfo.getContextName() << "' [URL=" << appInfo.getURL() 01733 << "].\n\n" 01734 << "Xoap message failure. Did the target Supervisor crash? Try " 01735 "re-initializing or restarting otsdaq." 01736 << __E__; 01737 __COUT_ERR__ << ss.str(); 01738 __MOUT_ERR__ << ss.str(); 01739 01740 try 01741 { 01742 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01743 << "Try again.." << __E__; 01744 01745 { 01746 // add a second try parameter flag 01747 SOAPParameters parameters; 01748 parameters.addParameter("retransmission", "1"); 01749 SOAPUtilities::addParameters(message, parameters); 01750 } 01751 01752 { 01753 // add the message index 01754 SOAPParameters parameters; 01755 { // mutex scope 01756 std::lock_guard<std::mutex> lock( 01757 broadcastCommandMessageIndexMutex_); 01758 parameters.addParameter("commandId", 01759 broadcastCommandMessageIndex_++); 01760 } // end mutex scope 01761 SOAPUtilities::addParameters(message, parameters); 01762 } 01763 01764 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01765 << "Re-Sending... " << SOAPUtilities::translate(message) 01766 << std::endl; 01767 01768 reply = send(appInfo.getDescriptor(), message); 01769 } 01770 catch(const xdaq::exception::Exception& e) // due to xoap send failure 01771 { 01772 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01773 << "Second try failed.." << __E__; 01774 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01775 } 01776 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01777 << "2nd try passed.." << __E__; 01778 } // end send catch 01779 01780 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01781 << "Reply received = " << reply << __E__; 01782 01783 if((reply != command + "Done") && (reply != command + "Response") && 01784 (reply != command + "Iterate") && (reply != command + "SubIterate")) 01785 { 01786 __SS__ << "Error! Gateway Supervisor can NOT " << command 01787 << " Supervisor instance = '" << appInfo.getName() 01788 << "' [LID=" << appInfo.getId() << "] in Context '" 01789 << appInfo.getContextName() << "' [URL=" << appInfo.getURL() 01790 << "].\n\n" 01791 << reply; 01792 __COUT_ERR__ << ss.str() << __E__; 01793 __MOUT_ERR__ << ss.str() << __E__; 01794 01795 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01796 << "Getting error message..." << __E__; 01797 try 01798 { 01799 xoap::MessageReference errorMessage = 01800 sendWithSOAPReply(appInfo.getDescriptor(), 01801 SOAPUtilities::makeSOAPMessageReference( 01802 "StateMachineErrorMessageRequest")); 01803 SOAPParameters parameters; 01804 parameters.addParameter("ErrorMessage"); 01805 SOAPUtilities::receive(errorMessage, parameters); 01806 01807 std::string error = parameters.getValue("ErrorMessage"); 01808 if(error == "") 01809 { 01810 std::stringstream err; 01811 err << "Unknown error from Supervisor instance = '" 01812 << appInfo.getName() << "' [LID=" << appInfo.getId() 01813 << "] in Context '" << appInfo.getContextName() 01814 << "' [URL=" << appInfo.getURL() 01815 << "]. If the problem persists or is repeatable, please notify " 01816 "admins.\n\n"; 01817 error = err.str(); 01818 } 01819 01820 __SS__ << "Received error from Supervisor instance = '" 01821 << appInfo.getName() << "' [LID=" << appInfo.getId() 01822 << "] in Context '" << appInfo.getContextName() 01823 << "' [URL=" << appInfo.getURL() 01824 << "].\n\n Error Message = " << error << __E__; 01825 01826 __COUT_ERR__ << ss.str() << __E__; 01827 __MOUT_ERR__ << ss.str() << __E__; 01828 01829 if(command == "Error") 01830 return true; // do not throw exception and exit loop if informing all 01831 // apps about error 01832 // else throw exception and go into Error 01833 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01834 } 01835 catch(const xdaq::exception::Exception& e) // due to xoap send failure 01836 { 01837 // do not kill whole system if xdaq xoap failure 01838 __SS__ << "Error! Gateway Supervisor failed to read error message from " 01839 "Supervisor instance = '" 01840 << appInfo.getName() << "' [LID=" << appInfo.getId() 01841 << "] in Context '" << appInfo.getContextName() 01842 << "' [URL=" << appInfo.getURL() << "].\n\n" 01843 << "Xoap message failure. Did the target Supervisor crash? Try " 01844 "re-initializing or restarting otsdaq." 01845 << __E__; 01846 __COUT_ERR__ << ss.str(); 01847 __MOUT_ERR__ << ss.str(); 01848 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 01849 } 01850 } // end error response handling 01851 else if(reply == command + "Iterate") 01852 { 01853 // when 'Working' this front-end is expecting 01854 // to get the same command again with an incremented iteration index 01855 // after all other front-ends see the same iteration index, and all 01856 // front-ends with higher priority see the incremented iteration index. 01857 01858 iterationsDone = false; 01859 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01860 << "Supervisor instance = '" << appInfo.getName() 01861 << "' [LID=" << appInfo.getId() << "] in Context '" 01862 << appInfo.getContextName() << "' [URL=" << appInfo.getURL() 01863 << "] flagged for another iteration to " << command 01864 << "... (iteration: " << iteration << ")" << __E__; 01865 01866 } // end still working response handling 01867 else if(reply == command + "SubIterate") 01868 { 01869 // when 'Working' this front-end is expecting 01870 // to get the same command again with an incremented sub-iteration index 01871 // without any other front-ends taking actions or seeing the sub-iteration 01872 // index. 01873 01874 subIterationsDone = false; 01875 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01876 << "Supervisor instance = '" << appInfo.getName() 01877 << "' [LID=" << appInfo.getId() << "] in Context '" 01878 << appInfo.getContextName() << "' [URL=" << appInfo.getURL() 01879 << "] flagged for another sub-iteration to " << command 01880 << "... (iteration: " << iteration 01881 << ", sub-iteration: " << subIteration << ")" << __E__; 01882 } 01883 else // else success response 01884 { 01885 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01886 << "Supervisor instance = '" << appInfo.getName() 01887 << "' [LID=" << appInfo.getId() << "] in Context '" 01888 << appInfo.getContextName() << "' [URL=" << appInfo.getURL() 01889 << "] was " << command << "'d correctly!" << __E__; 01890 } 01891 01892 if(subIteration) 01893 __COUT__ << "Broadcast thread " << threadIndex << "\t" 01894 << "Completed sub-iteration: " << subIteration << __E__; 01895 ++subIteration; 01896 01897 } // end subIteration handling loop 01898 01899 return iterationsDone; 01900 01901 } // end handleBroadcastMessageTarget() 01902 01903 //======================================================================================================================== 01904 // broadcastMessageThread 01905 // Sends message and gets reply 01906 // if failure, reply THROW 01907 void GatewaySupervisor::broadcastMessageThread( 01908 GatewaySupervisor* supervisorPtr, 01909 GatewaySupervisor::BroadcastThreadStruct* threadStruct) 01910 { 01911 __COUT__ << "Broadcast thread " << threadStruct->threadIndex_ << "\t" 01912 << "starting..." << __E__; 01913 01914 while(!threadStruct->exitThread_) 01915 { 01916 // sleep to give time to main thread to dole out work 01917 usleep(1000 /* 1ms */); 01918 01919 // take lock for remainder of scope 01920 std::lock_guard<std::mutex> lock(threadStruct->threadMutex); 01921 if(threadStruct->workToDo_) 01922 { 01923 __COUT__ << "Broadcast thread " << threadStruct->threadIndex_ << "\t" 01924 << "starting work..." << __E__; 01925 01926 try 01927 { 01928 if(supervisorPtr->handleBroadcastMessageTarget( 01929 threadStruct->getAppInfo(), 01930 threadStruct->getMessage(), 01931 threadStruct->getCommand(), 01932 threadStruct->getIteration(), 01933 threadStruct->getReply(), 01934 threadStruct->threadIndex_)) 01935 threadStruct->getIterationsDone() = true; 01936 } 01937 catch(toolbox::fsm::exception::Exception e) 01938 { 01939 __COUT__ << "Broadcast thread " << threadStruct->threadIndex_ << "\t" 01940 << "going into error: " << e.what() << __E__; 01941 01942 threadStruct->getReply() = e.what(); 01943 threadStruct->error_ = true; 01944 threadStruct->workToDo_ = false; 01945 threadStruct->working_ = false; // indicate exiting 01946 return; 01947 } 01948 01949 if(!threadStruct->getIterationsDone()) 01950 { 01951 __COUT__ << "Broadcast thread " << threadStruct->threadIndex_ << "\t" 01952 << "flagged for another iteration." << __E__; 01953 01954 // set global iterationsDone 01955 std::lock_guard<std::mutex> lock( 01956 supervisorPtr->broadcastIterationsDoneMutex_); 01957 supervisorPtr->broadcastIterationsDone_ = false; 01958 } 01959 01960 __COUT__ << "Broadcast thread " << threadStruct->threadIndex_ << "\t" 01961 << "done with work." << __E__; 01962 01963 threadStruct->workToDo_ = false; 01964 } // end work 01965 01966 } // end primary while loop 01967 01968 __COUT__ << "Broadcast thread " << threadStruct->threadIndex_ << "\t" 01969 << "exited." << __E__; 01970 threadStruct->working_ = false; // indicate exiting 01971 } // end broadcastMessageThread() 01972 01973 //======================================================================================================================== 01974 // broadcastMessage 01975 // Broadcast state transition to all xdaq Supervisors. 01976 // - Transition in order of priority as given by AllSupervisorInfo 01977 // Update Supervisor Info based on result of transition. 01978 void GatewaySupervisor::broadcastMessage(xoap::MessageReference message) 01979 { 01980 RunControlStateMachine::theProgressBar_.step(); 01981 01982 // transition of Gateway Supervisor is assumed successful so update status 01983 allSupervisorInfo_.setSupervisorStatus(this, theStateMachine_.getCurrentStateName()); 01984 01985 std::string command = SOAPUtilities::translate(message).getCommand(); 01986 01987 std::string reply; 01988 broadcastIterationsDone_ = false; 01989 bool assignedJob; 01990 01991 std::vector<std::vector<const SupervisorInfo*>> orderedSupervisors; 01992 01993 try 01994 { 01995 orderedSupervisors = allSupervisorInfo_.getOrderedSupervisorDescriptors(command); 01996 } 01997 catch(const std::runtime_error& e) 01998 { 01999 __SS__ << "Error getting supervisor priority. Was there a change in the context?" 02000 << " Remember, if the context was changed, it is safest to relaunch " 02001 "StartOTS.sh. " 02002 << e.what() << __E__; 02003 XCEPT_RAISE(toolbox::fsm::exception::Exception, ss.str()); 02004 } 02005 02006 RunControlStateMachine::theProgressBar_.step(); 02007 02008 // std::vector<std::vector<uint8_t/*bool*/>> supervisorIterationsDone; //Note: can not 02009 // use bool because std::vector does not allow access by reference of type bool 02010 GatewaySupervisor::BroadcastMessageIterationsDoneStruct supervisorIterationsDone; 02011 02012 // initialize to false (not done) 02013 for(const auto& vectorAtPriority : orderedSupervisors) 02014 supervisorIterationsDone.push( 02015 vectorAtPriority.size()); // push_back( 02016 // std::vector<uint8_t>(vectorAtPriority.size(), 02017 // false /*initial value*/)); 02018 02019 unsigned int iteration = 0; 02020 unsigned int subIteration; 02021 02022 // send command to all supervisors (for multiple iterations) until all are done 02023 02024 // make a copy of the message to use as starting point for iterations 02025 xoap::MessageReference originalMessage = 02026 SOAPUtilities::makeSOAPMessageReference(SOAPUtilities::translate(message)); 02027 02028 __COUT__ << "=========> Broadcasting state machine command = " << command << __E__; 02029 02030 unsigned int numberOfThreads = 1; 02031 02032 try 02033 { 02034 numberOfThreads = CorePropertySupervisorBase::getSupervisorTableNode() 02035 .getNode("NumberOfStateMachineBroadcastThreads") 02036 .getValue<unsigned int>(); 02037 } 02038 catch(...) 02039 { 02040 // ignore error for backwards compatibility 02041 __COUT__ << "Number of threads not in configuration, so defaulting to " 02042 << numberOfThreads << __E__; 02043 } 02044 02045 // Note: if 1 thread, then create no threads 02046 // i.e. only create threads if 2 or more. 02047 if(numberOfThreads == 1) 02048 numberOfThreads = 0; 02049 02050 __COUTV__(numberOfThreads); 02051 02052 std::vector<GatewaySupervisor::BroadcastThreadStruct> broadcastThreadStructs( 02053 numberOfThreads); 02054 02055 // only launch threads if more than 1 02056 // if 1, just use main thread 02057 for(unsigned int i = 0; i < numberOfThreads; ++i) 02058 { 02059 broadcastThreadStructs[i].threadIndex_ = i; 02060 02061 std::thread( 02062 [](GatewaySupervisor* supervisorPtr, 02063 GatewaySupervisor::BroadcastThreadStruct* threadStruct) { 02064 GatewaySupervisor::broadcastMessageThread(supervisorPtr, threadStruct); 02065 }, 02066 this, 02067 &broadcastThreadStructs[i]) 02068 .detach(); 02069 } // end broadcast thread creation loop 02070 02071 RunControlStateMachine::theProgressBar_.step(); 02072 02073 try 02074 { 02075 //::::::::::::::::::::::::::::::::::::::::::::::::::::: 02076 // Send a SOAP message to every Supervisor in order by priority 02077 do // while !iterationsDone 02078 { 02079 broadcastIterationsDone_ = true; 02080 02081 if(iteration) 02082 __COUT__ << "Starting iteration: " << iteration << __E__; 02083 02084 for(unsigned int i = 0; i < supervisorIterationsDone.size(); ++i) 02085 { 02086 for(unsigned int j = 0; j < supervisorIterationsDone.size(i); ++j) 02087 { 02088 checkForAsyncError(); 02089 02090 if(supervisorIterationsDone[i][j]) 02091 continue; // skip if supervisor is already done 02092 02093 const SupervisorInfo& appInfo = *(orderedSupervisors[i][j]); 02094 02095 // re-acquire original message 02096 message = SOAPUtilities::makeSOAPMessageReference( 02097 SOAPUtilities::translate(originalMessage)); 02098 02099 // add iteration index to message 02100 if(iteration) 02101 { 02102 // add the iteration index as a parameter to message 02103 SOAPParameters parameters; 02104 parameters.addParameter("iterationIndex", iteration); 02105 SOAPUtilities::addParameters(message, parameters); 02106 } 02107 02108 if(numberOfThreads) 02109 { 02110 // schedule message to first open thread 02111 assignedJob = false; 02112 do 02113 { 02114 for(unsigned int k = 0; k < numberOfThreads; ++k) 02115 { 02116 if(!broadcastThreadStructs[k].workToDo_) 02117 { 02118 // found our thread! 02119 assignedJob = true; 02120 __COUT__ << "Giving work to thread " << k << __E__; 02121 02122 std::lock_guard<std::mutex> lock( 02123 broadcastThreadStructs[k].threadMutex); 02124 broadcastThreadStructs[k].setMessage( 02125 appInfo, 02126 message, 02127 command, 02128 iteration, 02129 supervisorIterationsDone[i][j]); 02130 02131 break; 02132 } 02133 } // end thread assigning search 02134 02135 if(!assignedJob) 02136 { 02137 __COUT__ << "No free broadcast threads, " 02138 << "waiting for an available thread..." << __E__; 02139 usleep(100 * 1000 /*100 ms*/); 02140 } 02141 } while(!assignedJob); 02142 } 02143 else // no thread 02144 { 02145 if(handleBroadcastMessageTarget( 02146 appInfo, message, command, iteration, reply)) 02147 supervisorIterationsDone[i][j] = true; 02148 else 02149 broadcastIterationsDone_ = false; 02150 } 02151 02152 } // end supervisors at same priority broadcast loop 02153 02154 // before proceeding to next priority, 02155 // make sure all threads have completed 02156 if(numberOfThreads) 02157 { 02158 __COUT__ 02159 << "Done with priority level. Waiting for threads to finish..." 02160 << __E__; 02161 bool done; 02162 do 02163 { 02164 done = true; 02165 for(unsigned int i = 0; i < numberOfThreads; ++i) 02166 if(broadcastThreadStructs[i].workToDo_) 02167 { 02168 done = false; 02169 __COUT__ << "Still waiting on thread " << i << "..." 02170 << __E__; 02171 usleep(100 * 1000 /*100ms*/); 02172 break; 02173 } 02174 else if(broadcastThreadStructs[i].error_) 02175 { 02176 __COUT__ << "Found thread in error! Throwing state " 02177 "machine error: " 02178 << broadcastThreadStructs[i].getReply() << __E__; 02179 XCEPT_RAISE(toolbox::fsm::exception::Exception, 02180 broadcastThreadStructs[i].getReply()); 02181 } 02182 } while(!done); 02183 __COUT__ << "All threads done with priority level work." << __E__; 02184 } // end thread complete verification 02185 02186 } // end supervisor broadcast loop for each priority 02187 02188 // if (!proceed) 02189 // { 02190 // __COUT__ << "Breaking out of primary loop." << __E__; 02191 // break; 02192 // } 02193 02194 if(iteration || !broadcastIterationsDone_) 02195 __COUT__ << "Completed iteration: " << iteration << __E__; 02196 ++iteration; 02197 02198 } while(!broadcastIterationsDone_); 02199 02200 RunControlStateMachine::theProgressBar_.step(); 02201 } // end main transition broadcast try 02202 catch(...) 02203 { 02204 __COUT__ << "Exception caught, exiting broadcast threads..." << __E__; 02205 02206 // attempt to exit threads 02207 // The threads should already be done with all work. 02208 // If broadcastMessage scope ends, then the 02209 // thread struct will be destructed, and the thread will 02210 // crash on next access attempt (thought we probably do not care). 02211 for(unsigned int i = 0; i < numberOfThreads; ++i) 02212 broadcastThreadStructs[i].exitThread_ = true; 02213 usleep(100 * 1000 /*100ms*/); // sleep for exit time 02214 02215 throw; // re-throw 02216 } 02217 02218 if(numberOfThreads) 02219 { 02220 __COUT__ << "All transitions completed. Wrapping up, exiting broadcast threads..." 02221 << __E__; 02222 02223 // attempt to exit threads 02224 // The threads should already be done with all work. 02225 // If broadcastMessage scope ends, then the 02226 // thread struct will be destructed, and the thread will 02227 // crash on next access attempt (when the thread crashes, the whole context 02228 // crashes). 02229 for(unsigned int i = 0; i < numberOfThreads; ++i) 02230 broadcastThreadStructs[i].exitThread_ = true; 02231 usleep(100 * 1000 /*100ms*/); // sleep for exit time 02232 } 02233 02234 __COUT__ << "Broadcast complete." << __E__; 02235 } // end broadcastMessage() 02236 02237 //======================================================================================================================== 02238 void GatewaySupervisor::wait(int milliseconds, std::string who) const 02239 { 02240 for(int s = 1; s <= milliseconds; s++) 02241 { 02242 usleep(1000); 02243 02244 if(s % 100 == 0) 02245 __COUT__ << s << " msecs " << who << __E__; 02246 } 02247 } 02248 02249 //======================================================================================================================== 02250 // LoginRequest 02251 // handles all users login/logout actions from web GUI. 02252 // NOTE: there are two ways for a user to be logged out: timeout or manual logout 02253 // System logbook messages are generated for login and logout 02254 void GatewaySupervisor::loginRequest(xgi::Input* in, xgi::Output* out) 02255 { 02256 __COUT__ << "Start" << __E__; 02257 cgicc::Cgicc cgi(in); 02258 std::string Command = CgiDataUtilities::getData(cgi, "RequestType"); 02259 __COUT__ << "*** Login RequestType = " << Command << __E__; 02260 02261 // RequestType Commands: 02262 // login 02263 // sessionId 02264 // checkCookie 02265 // logout 02266 02267 // always cleanup expired entries and get a vector std::string of logged out users 02268 std::vector<std::string> loggedOutUsernames; 02269 theWebUsers_.cleanupExpiredEntries(&loggedOutUsernames); 02270 for(unsigned int i = 0; i < loggedOutUsernames.size(); 02271 ++i) // Log logout for logged out users 02272 makeSystemLogbookEntry(loggedOutUsernames[i] + " login timed out."); 02273 02274 if(Command == "sessionId") 02275 { 02276 // When client loads page, client submits unique user id and receives random 02277 // sessionId from server Whenever client submits user name and password it is 02278 // jumbled by sessionId when sent to server and sent along with UUID. Server uses 02279 // sessionId to unjumble. 02280 // 02281 // Server maintains list of active sessionId by UUID 02282 // sessionId expires after set time if no login attempt (e.g. 5 minutes) 02283 std::string uuid = CgiDataUtilities::postData(cgi, "uuid"); 02284 02285 std::string sid = theWebUsers_.createNewLoginSession( 02286 uuid, cgi.getEnvironment().getRemoteAddr() /* ip */); 02287 02288 // __COUT__ << "uuid = " << uuid << __E__; 02289 // __COUT__ << "SessionId = " << sid.substr(0, 10) << __E__; 02290 *out << sid; 02291 } 02292 else if(Command == "checkCookie") 02293 { 02294 uint64_t uid; 02295 std::string uuid; 02296 std::string jumbledUser; 02297 std::string cookieCode; 02298 02299 // If client has a cookie, client submits cookie and username, jumbled, to see if 02300 // cookie and user are still active if active, valid cookie code is returned 02301 // and name to display, in XML 02302 // if not, return 0 02303 // params: 02304 // uuid - unique user id, to look up sessionId 02305 // ju - jumbled user name 02306 // CookieCode - cookie code to check 02307 02308 uuid = CgiDataUtilities::postData(cgi, "uuid"); 02309 jumbledUser = CgiDataUtilities::postData(cgi, "ju"); 02310 cookieCode = CgiDataUtilities::postData(cgi, "cc"); 02311 02312 // __COUT__ << "uuid = " << uuid << __E__; 02313 // __COUT__ << "Cookie Code = " << cookieCode.substr(0, 10) << __E__; 02314 // __COUT__ << "jumbledUser = " << jumbledUser.substr(0, 10) << __E__; 02315 02316 // If cookie code is good, then refresh and return with display name, else return 02317 // 0 as CookieCode value 02318 uid = theWebUsers_.isCookieCodeActiveForLogin( 02319 uuid, 02320 cookieCode, 02321 jumbledUser); // after call jumbledUser holds displayName on success 02322 02323 if(uid == theWebUsers_.NOT_FOUND_IN_DATABASE) 02324 { 02325 __COUT__ << "cookieCode invalid" << __E__; 02326 jumbledUser = ""; // clear display name if failure 02327 cookieCode = "0"; // clear cookie code if failure 02328 } 02329 else 02330 __COUT__ << "cookieCode is good." << __E__; 02331 02332 // return xml holding cookie code and display name 02333 HttpXmlDocument xmldoc(cookieCode, jumbledUser); 02334 02335 theWebUsers_.insertSettingsForUser(uid, &xmldoc); // insert settings 02336 02337 xmldoc.outputXmlDocument((std::ostringstream*)out); 02338 } 02339 else if(Command == "login") 02340 { 02341 // If login attempt or create account, jumbled user and pw are submitted 02342 // if successful, valid cookie code and display name returned. 02343 // if not, return 0 02344 // params: 02345 // uuid - unique user id, to look up sessionId 02346 // nac - new account code for first time logins 02347 // ju - jumbled user name 02348 // jp - jumbled password 02349 02350 std::string uuid = CgiDataUtilities::postData(cgi, "uuid"); 02351 std::string newAccountCode = CgiDataUtilities::postData(cgi, "nac"); 02352 std::string jumbledUser = CgiDataUtilities::postData(cgi, "ju"); 02353 std::string jumbledPw = CgiDataUtilities::postData(cgi, "jp"); 02354 02355 // __COUT__ << "jumbledUser = " << jumbledUser.substr(0, 10) << __E__; 02356 // __COUT__ << "jumbledPw = " << jumbledPw.substr(0, 10) << __E__; 02357 // __COUT__ << "uuid = " << uuid << __E__; 02358 // __COUT__ << "nac =-" << newAccountCode << "-" << __E__; 02359 02360 uint64_t uid = theWebUsers_.attemptActiveSession( 02361 uuid, 02362 jumbledUser, 02363 jumbledPw, 02364 newAccountCode, 02365 cgi.getEnvironment() 02366 .getRemoteAddr()); // after call jumbledUser holds displayName on success 02367 02368 if(uid == theWebUsers_.NOT_FOUND_IN_DATABASE) 02369 { 02370 __COUT__ << "Login invalid." << __E__; 02371 jumbledUser = ""; // clear display name if failure 02372 if(newAccountCode != "1") // indicates uuid not found 02373 newAccountCode = "0"; // clear cookie code if failure 02374 } 02375 else // Log login in logbook for active experiment 02376 makeSystemLogbookEntry(theWebUsers_.getUsersUsername(uid) + " logged in."); 02377 02378 //__COUT__ << "new cookieCode = " << newAccountCode.substr(0, 10) << __E__; 02379 02380 HttpXmlDocument xmldoc(newAccountCode, jumbledUser); 02381 02382 theWebUsers_.insertSettingsForUser(uid, &xmldoc); // insert settings 02383 02384 // insert active session count for user 02385 02386 if(uid != theWebUsers_.NOT_FOUND_IN_DATABASE) 02387 { 02388 uint64_t asCnt = theWebUsers_.getActiveSessionCountForUser(uid) - 02389 1; // subtract 1 to remove just started session from count 02390 char asStr[20]; 02391 sprintf(asStr, "%lu", asCnt); 02392 xmldoc.addTextElementToData("user_active_session_count", asStr); 02393 } 02394 02395 xmldoc.outputXmlDocument((std::ostringstream*)out); 02396 } 02397 else if(Command == "cert") 02398 { 02399 // If login attempt or create account, jumbled user and pw are submitted 02400 // if successful, valid cookie code and display name returned. 02401 // if not, return 0 02402 // params: 02403 // uuid - unique user id, to look up sessionId 02404 // nac - new account code for first time logins 02405 // ju - jumbled user name 02406 // jp - jumbled password 02407 02408 std::string uuid = CgiDataUtilities::postData(cgi, "uuid"); 02409 std::string jumbledEmail = 02410 cgicc::form_urldecode(CgiDataUtilities::getData(cgi, "httpsUser")); 02411 std::string username = ""; 02412 std::string cookieCode = ""; 02413 02414 // __COUT__ << "CERTIFICATE LOGIN REUEST RECEVIED!!!" << __E__; 02415 // __COUT__ << "jumbledEmail = " << jumbledEmail << __E__; 02416 // __COUT__ << "uuid = " << uuid << __E__; 02417 02418 uint64_t uid = theWebUsers_.attemptActiveSessionWithCert( 02419 uuid, 02420 jumbledEmail, 02421 cookieCode, 02422 username, 02423 cgi.getEnvironment() 02424 .getRemoteAddr()); // after call jumbledUser holds displayName on success 02425 02426 if(uid == theWebUsers_.NOT_FOUND_IN_DATABASE) 02427 { 02428 __COUT__ << "cookieCode invalid" << __E__; 02429 jumbledEmail = ""; // clear display name if failure 02430 if(cookieCode != "1") // indicates uuid not found 02431 cookieCode = "0"; // clear cookie code if failure 02432 } 02433 else // Log login in logbook for active experiment 02434 makeSystemLogbookEntry(theWebUsers_.getUsersUsername(uid) + " logged in."); 02435 02436 //__COUT__ << "new cookieCode = " << cookieCode.substr(0, 10) << __E__; 02437 02438 HttpXmlDocument xmldoc(cookieCode, jumbledEmail); 02439 02440 theWebUsers_.insertSettingsForUser(uid, &xmldoc); // insert settings 02441 02442 // insert active session count for user 02443 02444 if(uid != theWebUsers_.NOT_FOUND_IN_DATABASE) 02445 { 02446 uint64_t asCnt = theWebUsers_.getActiveSessionCountForUser(uid) - 02447 1; // subtract 1 to remove just started session from count 02448 char asStr[20]; 02449 sprintf(asStr, "%lu", asCnt); 02450 xmldoc.addTextElementToData("user_active_session_count", asStr); 02451 } 02452 02453 xmldoc.outputXmlDocument((std::ostringstream*)out); 02454 } 02455 else if(Command == "logout") 02456 { 02457 std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode"); 02458 std::string logoutOthers = CgiDataUtilities::postData(cgi, "LogoutOthers"); 02459 02460 // __COUT__ << "Cookie Code = " << cookieCode.substr(0, 10) << __E__; 02461 // __COUT__ << "logoutOthers = " << logoutOthers << __E__; 02462 02463 uint64_t uid; // get uid for possible system logbook message 02464 if(theWebUsers_.cookieCodeLogout(cookieCode, 02465 logoutOthers == "1", 02466 &uid, 02467 cgi.getEnvironment().getRemoteAddr()) != 02468 theWebUsers_.NOT_FOUND_IN_DATABASE) // user logout 02469 { 02470 // if did some logging out, check if completely logged out 02471 // if so, system logbook message should be made. 02472 if(!theWebUsers_.isUserIdActive(uid)) 02473 makeSystemLogbookEntry(theWebUsers_.getUsersUsername(uid) + 02474 " logged out."); 02475 } 02476 } 02477 else 02478 { 02479 __COUT__ << "Invalid Command" << __E__; 02480 *out << "0"; 02481 } 02482 02483 __COUT__ << "Done" << __E__; 02484 } // end loginRequest() 02485 02486 //======================================================================================================================== 02487 void GatewaySupervisor::tooltipRequest(xgi::Input* in, xgi::Output* out) 02488 { 02489 __COUT__ << "Start" << __E__; 02490 cgicc::Cgicc cgi(in); 02491 02492 std::string Command = CgiDataUtilities::getData(cgi, "RequestType"); 02493 __COUT__ << "Tooltip RequestType = " << Command << __E__; 02494 02495 //**** start LOGIN GATEWAY CODE ***// 02496 // If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers 02497 // optionally for uint8_t userPermissions, uint64_t uid Else, error message is 02498 // returned in cookieCode Notes: cookie code not refreshed if RequestType = 02499 // getSystemMessages 02500 std::string cookieCode = CgiDataUtilities::postData(cgi, "CookieCode"); 02501 uint64_t uid; 02502 02503 if(!theWebUsers_.cookieCodeIsActiveForRequest( 02504 cookieCode, 0 /*userPermissions*/, &uid, "0" /*dummy ip*/, false /*refresh*/)) 02505 { 02506 *out << cookieCode; 02507 return; 02508 } 02509 02510 //**** end LOGIN GATEWAY CODE ***// 02511 02512 HttpXmlDocument xmldoc(cookieCode); 02513 02514 if(Command == "check") 02515 { 02516 WebUsers::tooltipCheckForUsername(theWebUsers_.getUsersUsername(uid), 02517 &xmldoc, 02518 CgiDataUtilities::getData(cgi, "srcFile"), 02519 CgiDataUtilities::getData(cgi, "srcFunc"), 02520 CgiDataUtilities::getData(cgi, "srcId")); 02521 } 02522 else if(Command == "setNeverShow") 02523 { 02524 WebUsers::tooltipSetNeverShowForUsername( 02525 theWebUsers_.getUsersUsername(uid), 02526 &xmldoc, 02527 CgiDataUtilities::getData(cgi, "srcFile"), 02528 CgiDataUtilities::getData(cgi, "srcFunc"), 02529 CgiDataUtilities::getData(cgi, "srcId"), 02530 CgiDataUtilities::getData(cgi, "doNeverShow") == "1" ? true : false, 02531 CgiDataUtilities::getData(cgi, "temporarySilence") == "1" ? true : false); 02532 } 02533 else 02534 __COUT__ << "Command Request, " << Command << ", not recognized." << __E__; 02535 02536 xmldoc.outputXmlDocument((std::ostringstream*)out, false, true); 02537 02538 __COUT__ << "Done" << __E__; 02539 } // end tooltipRequest 02540 02541 //======================================================================================================================== 02542 // setSupervisorPropertyDefaults 02543 // override to set defaults for supervisor property values (before user settings 02544 // override) 02545 void GatewaySupervisor::setSupervisorPropertyDefaults() 02546 { 02547 CorePropertySupervisorBase::setSupervisorProperty( 02548 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.UserPermissionsThreshold, 02549 std::string() + "*=1 | gatewayLaunchOTS=-1 | gatewayLaunchWiz=-1"); 02550 } 02551 02552 //======================================================================================================================== 02553 // forceSupervisorPropertyValues 02554 // override to force supervisor property values (and ignore user settings) 02555 void GatewaySupervisor::forceSupervisorPropertyValues() 02556 { 02557 // note used by these handlers: 02558 // request() 02559 // stateMachineXgiHandler() -- prepend StateMachine to request type 02560 02561 CorePropertySupervisorBase::setSupervisorProperty( 02562 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.AutomatedRequestTypes, 02563 "getSystemMessages | getCurrentState | getIterationPlanStatus"); 02564 CorePropertySupervisorBase::setSupervisorProperty( 02565 CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.RequireUserLockRequestTypes, 02566 "gatewayLaunchOTS | gatewayLaunchWiz"); 02567 // CorePropertySupervisorBase::setSupervisorProperty(CorePropertySupervisorBase::SUPERVISOR_PROPERTIES.NeedUsernameRequestTypes, 02568 // "StateMachine*"); //for all stateMachineXgiHandler requests 02569 } 02570 02571 //======================================================================================================================== 02572 void GatewaySupervisor::request(xgi::Input* in, xgi::Output* out) 02573 { 02574 //__COUT__ << "Start" << __E__; 02575 02576 // for simplicity assume all commands should be mutually exclusive with iterator 02577 // thread state machine accesses (really should just be careful with 02578 // RunControlStateMachine access) 02579 if(VERBOSE_MUTEX) 02580 __COUT__ << "Waiting for FSM access" << __E__; 02581 std::lock_guard<std::mutex> lock(stateMachineAccessMutex_); 02582 if(VERBOSE_MUTEX) 02583 __COUT__ << "Have FSM access" << __E__; 02584 02585 cgicc::Cgicc cgiIn(in); 02586 02587 std::string requestType = CgiDataUtilities::getData(cgiIn, "RequestType"); 02588 02589 HttpXmlDocument xmlOut; 02590 WebUsers::RequestUserInfo userInfo(requestType, 02591 CgiDataUtilities::postData(cgiIn, "CookieCode")); 02592 02593 CorePropertySupervisorBase::getRequestUserInfo(userInfo); 02594 02595 if(!theWebUsers_.xmlRequestOnGateway(cgiIn, out, &xmlOut, userInfo)) 02596 return; // access failed 02597 02598 // RequestType Commands: 02599 // getSettings 02600 // setSettings 02601 // accountSettings 02602 // getAliasList 02603 // getFecList 02604 // getSystemMessages 02605 // setUserWithLock 02606 // getStateMachine 02607 // stateMatchinePreferences 02608 // getStateMachineNames 02609 // getCurrentState 02610 // cancelStateMachineTransition 02611 // getIterationPlanStatus 02612 // getErrorInStateMatchine 02613 // getDesktopIcons 02614 02615 // resetUserTooltips 02616 02617 // gatewayLaunchOTS 02618 // gatewayLaunchWiz 02619 02620 try 02621 { 02622 if(requestType == "getSettings") 02623 { 02624 std::string accounts = CgiDataUtilities::getData(cgiIn, "accounts"); 02625 02626 __COUT__ << "Get Settings Request" << __E__; 02627 __COUT__ << "accounts = " << accounts << __E__; 02628 theWebUsers_.insertSettingsForUser(userInfo.uid_, &xmlOut, accounts == "1"); 02629 } 02630 else if(requestType == "setSettings") 02631 { 02632 std::string bgcolor = CgiDataUtilities::postData(cgiIn, "bgcolor"); 02633 std::string dbcolor = CgiDataUtilities::postData(cgiIn, "dbcolor"); 02634 std::string wincolor = CgiDataUtilities::postData(cgiIn, "wincolor"); 02635 std::string layout = CgiDataUtilities::postData(cgiIn, "layout"); 02636 std::string syslayout = CgiDataUtilities::postData(cgiIn, "syslayout"); 02637 02638 __COUT__ << "Set Settings Request" << __E__; 02639 __COUT__ << "bgcolor = " << bgcolor << __E__; 02640 __COUT__ << "dbcolor = " << dbcolor << __E__; 02641 __COUT__ << "wincolor = " << wincolor << __E__; 02642 __COUT__ << "layout = " << layout << __E__; 02643 __COUT__ << "syslayout = " << syslayout << __E__; 02644 02645 theWebUsers_.changeSettingsForUser( 02646 userInfo.uid_, bgcolor, dbcolor, wincolor, layout, syslayout); 02647 theWebUsers_.insertSettingsForUser( 02648 userInfo.uid_, &xmlOut, true); // include user accounts 02649 } 02650 else if(requestType == "accountSettings") 02651 { 02652 std::string type = CgiDataUtilities::postData( 02653 cgiIn, "type"); // updateAccount, createAccount, deleteAccount 02654 int type_int = -1; 02655 02656 if(type == "updateAccount") 02657 type_int = 0; 02658 else if(type == "createAccount") 02659 type_int = 1; 02660 else if(type == "deleteAccount") 02661 type_int = 2; 02662 02663 std::string username = CgiDataUtilities::postData(cgiIn, "username"); 02664 std::string displayname = CgiDataUtilities::postData(cgiIn, "displayname"); 02665 std::string email = CgiDataUtilities::postData(cgiIn, "useremail"); 02666 std::string permissions = CgiDataUtilities::postData(cgiIn, "permissions"); 02667 std::string accounts = CgiDataUtilities::getData(cgiIn, "accounts"); 02668 02669 __COUT__ << "accountSettings Request" << __E__; 02670 __COUT__ << "type = " << type << " - " << type_int << __E__; 02671 __COUT__ << "username = " << username << __E__; 02672 __COUT__ << "useremail = " << email << __E__; 02673 __COUT__ << "displayname = " << displayname << __E__; 02674 __COUT__ << "permissions = " << permissions << __E__; 02675 02676 theWebUsers_.modifyAccountSettings( 02677 userInfo.uid_, type_int, username, displayname, email, permissions); 02678 02679 __COUT__ << "accounts = " << accounts << __E__; 02680 02681 theWebUsers_.insertSettingsForUser(userInfo.uid_, &xmlOut, accounts == "1"); 02682 } 02683 else if(requestType == "stateMatchinePreferences") 02684 { 02685 std::string set = CgiDataUtilities::getData(cgiIn, "set"); 02686 const std::string DEFAULT_FSM_VIEW = "Default_FSM_View"; 02687 if(set == "1") 02688 theWebUsers_.setGenericPreference( 02689 userInfo.uid_, 02690 DEFAULT_FSM_VIEW, 02691 CgiDataUtilities::getData(cgiIn, DEFAULT_FSM_VIEW)); 02692 else 02693 theWebUsers_.getGenericPreference( 02694 userInfo.uid_, DEFAULT_FSM_VIEW, &xmlOut); 02695 } 02696 else if(requestType == "getAliasList") 02697 { 02698 std::string username = theWebUsers_.getUsersUsername(userInfo.uid_); 02699 std::string fsmName = CgiDataUtilities::getData(cgiIn, "fsmName"); 02700 __COUT__ << "fsmName = " << fsmName << __E__; 02701 02702 std::string stateMachineAliasFilter = "*"; // default to all 02703 02704 std::map<std::string /*alias*/, 02705 std::pair<std::string /*group name*/, TableGroupKey>> 02706 aliasMap = CorePropertySupervisorBase::theConfigurationManager_ 02707 ->getActiveGroupAliases(); 02708 02709 // get stateMachineAliasFilter if possible 02710 ConfigurationTree configLinkNode = 02711 CorePropertySupervisorBase::theConfigurationManager_ 02712 ->getSupervisorTableNode(supervisorContextUID_, 02713 supervisorApplicationUID_); 02714 02715 if(!configLinkNode.isDisconnected()) 02716 { 02717 try // for backwards compatibility 02718 { 02719 ConfigurationTree fsmLinkNode = 02720 configLinkNode.getNode("LinkToStateMachineTable"); 02721 if(!fsmLinkNode.isDisconnected()) 02722 stateMachineAliasFilter = 02723 fsmLinkNode.getNode(fsmName + "/SystemAliasFilter") 02724 .getValue<std::string>(); 02725 else 02726 __COUT_INFO__ << "FSM Link disconnected." << __E__; 02727 } 02728 catch(std::runtime_error& e) 02729 { 02730 __COUT_INFO__ << e.what() << __E__; 02731 } 02732 catch(...) 02733 { 02734 __COUT_ERR__ << "Unknown error. Should never happen." << __E__; 02735 } 02736 } 02737 else 02738 __COUT_INFO__ << "FSM Link disconnected." << __E__; 02739 02740 __COUT__ << "stateMachineAliasFilter = " << stateMachineAliasFilter << __E__; 02741 02742 // filter list of aliases based on stateMachineAliasFilter 02743 // ! as first character means choose those that do NOT match filter 02744 // * can be used as wild card. 02745 { 02746 bool invertFilter = 02747 stateMachineAliasFilter.size() && stateMachineAliasFilter[0] == '!'; 02748 std::vector<std::string> filterArr; 02749 02750 size_t i = 0; 02751 if(invertFilter) 02752 ++i; 02753 size_t f; 02754 std::string tmp; 02755 while((f = stateMachineAliasFilter.find('*', i)) != std::string::npos) 02756 { 02757 tmp = stateMachineAliasFilter.substr(i, f - i); 02758 i = f + 1; 02759 filterArr.push_back(tmp); 02760 //__COUT__ << filterArr[filterArr.size()-1] << " " << i << 02761 // " of " << stateMachineAliasFilter.size() << __E__; 02762 } 02763 if(i <= stateMachineAliasFilter.size()) 02764 { 02765 tmp = stateMachineAliasFilter.substr(i); 02766 filterArr.push_back(tmp); 02767 //__COUT__ << filterArr[filterArr.size()-1] << " last." << __E__; 02768 } 02769 02770 bool filterMatch; 02771 02772 for(auto& aliasMapPair : aliasMap) 02773 { 02774 //__COUT__ << "aliasMapPair.first: " << aliasMapPair.first << __E__; 02775 02776 filterMatch = true; 02777 02778 if(filterArr.size() == 1) 02779 { 02780 if(filterArr[0] != "" && filterArr[0] != "*" && 02781 aliasMapPair.first != filterArr[0]) 02782 filterMatch = false; 02783 } 02784 else 02785 { 02786 i = -1; 02787 for(f = 0; f < filterArr.size(); ++f) 02788 { 02789 if(!filterArr[f].size()) 02790 continue; // skip empty filters 02791 02792 if(f == 0) // must start with this filter 02793 { 02794 if((i = aliasMapPair.first.find(filterArr[f])) != 0) 02795 { 02796 filterMatch = false; 02797 break; 02798 } 02799 } 02800 else if(f == 02801 filterArr.size() - 1) // must end with this filter 02802 { 02803 if(aliasMapPair.first.rfind(filterArr[f]) != 02804 aliasMapPair.first.size() - filterArr[f].size()) 02805 { 02806 filterMatch = false; 02807 break; 02808 } 02809 } 02810 else if((i = aliasMapPair.first.find(filterArr[f])) == 02811 std::string::npos) 02812 { 02813 filterMatch = false; 02814 break; 02815 } 02816 } 02817 } 02818 02819 if(invertFilter) 02820 filterMatch = !filterMatch; 02821 02822 //__COUT__ << "filterMatch=" << filterMatch << __E__; 02823 02824 if(!filterMatch) 02825 continue; 02826 02827 xmlOut.addTextElementToData("config_alias", aliasMapPair.first); 02828 xmlOut.addTextElementToData( 02829 "config_key", 02830 TableGroupKey::getFullGroupString(aliasMapPair.second.first, 02831 aliasMapPair.second.second) 02832 .c_str()); 02833 02834 std::string groupComment, groupAuthor, groupCreationTime; 02835 try 02836 { 02837 CorePropertySupervisorBase::theConfigurationManager_ 02838 ->loadTableGroup(aliasMapPair.second.first, 02839 aliasMapPair.second.second, 02840 false, 02841 0, 02842 0, 02843 0, 02844 &groupComment, 02845 &groupAuthor, 02846 &groupCreationTime, 02847 false /*false to not load member map*/); 02848 02849 xmlOut.addTextElementToData("config_comment", groupComment); 02850 xmlOut.addTextElementToData("config_author", groupAuthor); 02851 xmlOut.addTextElementToData("config_create_time", 02852 groupCreationTime); 02853 } 02854 catch(...) 02855 { 02856 __COUT_WARN__ << "Failed to load group metadata." << __E__; 02857 } 02858 } 02859 } 02860 02861 // return last group alias 02862 std::string fn = FSM_LAST_GROUP_ALIAS_PATH + FSM_LAST_GROUP_ALIAS_FILE_START + 02863 username + "." + FSM_USERS_PREFERENCES_FILETYPE; 02864 __COUT__ << "Load preferences: " << fn << __E__; 02865 FILE* fp = fopen(fn.c_str(), "r"); 02866 if(fp) 02867 { 02868 char tmpLastAlias[500]; 02869 fscanf(fp, "%*s %s", tmpLastAlias); 02870 __COUT__ << "tmpLastAlias: " << tmpLastAlias << __E__; 02871 02872 xmlOut.addTextElementToData("UserLastConfigAlias", tmpLastAlias); 02873 fclose(fp); 02874 } 02875 } 02876 else if(requestType == "getFecList") 02877 { 02878 xmlOut.addTextElementToData("fec_list", ""); 02879 02880 for(auto it : allSupervisorInfo_.getAllFETypeSupervisorInfo()) 02881 { 02882 xmlOut.addTextElementToParent("fec_url", it.second.getURL(), "fec_list"); 02883 xmlOut.addTextElementToParent( 02884 "fec_urn", std::to_string(it.second.getId()), "fec_list"); 02885 } 02886 } 02887 else if(requestType == "getSystemMessages") 02888 { 02889 xmlOut.addTextElementToData( 02890 "systemMessages", 02891 theSystemMessenger_.getSystemMessage( 02892 theWebUsers_.getUsersDisplayName(userInfo.uid_))); 02893 02894 xmlOut.addTextElementToData( 02895 "username_with_lock", 02896 theWebUsers_.getUserWithLock()); // always give system lock update 02897 02898 //__COUT__ << "userWithLock " << theWebUsers_.getUserWithLock() << __E__; 02899 } 02900 else if(requestType == "setUserWithLock") 02901 { 02902 std::string username = CgiDataUtilities::postData(cgiIn, "username"); 02903 std::string lock = CgiDataUtilities::postData(cgiIn, "lock"); 02904 std::string accounts = CgiDataUtilities::getData(cgiIn, "accounts"); 02905 02906 __COUT__ << requestType << __E__; 02907 __COUT__ << "username " << username << __E__; 02908 __COUT__ << "lock " << lock << __E__; 02909 __COUT__ << "accounts " << accounts << __E__; 02910 __COUT__ << "userInfo.uid_ " << userInfo.uid_ << __E__; 02911 02912 std::string tmpUserWithLock = theWebUsers_.getUserWithLock(); 02913 if(!theWebUsers_.setUserWithLock(userInfo.uid_, lock == "1", username)) 02914 xmlOut.addTextElementToData( 02915 "server_alert", 02916 std::string("Set user lock action failed. You must have valid " 02917 "permissions and ") + 02918 "locking user must be currently logged in."); 02919 02920 theWebUsers_.insertSettingsForUser(userInfo.uid_, &xmlOut, accounts == "1"); 02921 02922 if(tmpUserWithLock != 02923 theWebUsers_ 02924 .getUserWithLock()) // if there was a change, broadcast system message 02925 theSystemMessenger_.addSystemMessage( 02926 "*", 02927 theWebUsers_.getUserWithLock() == "" 02928 ? tmpUserWithLock + " has unlocked ots." 02929 : theWebUsers_.getUserWithLock() + " has locked ots."); 02930 } 02931 else if(requestType == "getStateMachine") 02932 { 02933 // __COUT__ << "Getting state machine" << __E__; 02934 std::vector<toolbox::fsm::State> states; 02935 states = theStateMachine_.getStates(); 02936 char stateStr[2]; 02937 stateStr[1] = '\0'; 02938 std::string transName; 02939 std::string transParameter; 02940 02941 // bool addRun, addCfg; 02942 for(unsigned int i = 0; i < states.size(); ++i) // get all states 02943 { 02944 stateStr[0] = states[i]; 02945 DOMElement* stateParent = xmlOut.addTextElementToData("state", stateStr); 02946 02947 xmlOut.addTextElementToParent( 02948 "state_name", theStateMachine_.getStateName(states[i]), stateParent); 02949 02950 //__COUT__ << "state: " << states[i] << " - " << 02951 // theStateMachine_.getStateName(states[i]) << __E__; 02952 02953 // get all transition final states, transitionNames and actionNames from 02954 // state 02955 std::map<std::string, toolbox::fsm::State, std::less<std::string>> trans = 02956 theStateMachine_.getTransitions(states[i]); 02957 std::set<std::string> actionNames = theStateMachine_.getInputs(states[i]); 02958 02959 std::map<std::string, toolbox::fsm::State, std::less<std::string>>:: 02960 iterator it = trans.begin(); 02961 std::set<std::string>::iterator ait = actionNames.begin(); 02962 02963 // addRun = false; 02964 // addCfg = false; 02965 02966 // handle hacky way to keep "forward" moving states on right of FSM 02967 // display must be first! 02968 02969 for(; it != trans.end() && ait != actionNames.end(); ++it, ++ait) 02970 { 02971 stateStr[0] = it->second; 02972 02973 if(stateStr[0] == 'R') 02974 { 02975 // addRun = true; 02976 xmlOut.addTextElementToParent( 02977 "state_transition", stateStr, stateParent); 02978 02979 //__COUT__ << states[i] << " => " << *ait << __E__; 02980 02981 xmlOut.addTextElementToParent( 02982 "state_transition_action", *ait, stateParent); 02983 02984 transName = theStateMachine_.getTransitionName(states[i], *ait); 02985 //__COUT__ << states[i] << " => " << transName << __E__; 02986 02987 xmlOut.addTextElementToParent( 02988 "state_transition_name", transName, stateParent); 02989 transParameter = 02990 theStateMachine_.getTransitionParameter(states[i], *ait); 02991 //__COUT__ << states[i] << " => " << transParameter<< __E__; 02992 02993 xmlOut.addTextElementToParent( 02994 "state_transition_parameter", transParameter, stateParent); 02995 break; 02996 } 02997 else if(stateStr[0] == 'C') 02998 { 02999 // addCfg = true; 03000 xmlOut.addTextElementToParent( 03001 "state_transition", stateStr, stateParent); 03002 03003 //__COUT__ << states[i] << " => " << *ait << __E__; 03004 03005 xmlOut.addTextElementToParent( 03006 "state_transition_action", *ait, stateParent); 03007 03008 transName = theStateMachine_.getTransitionName(states[i], *ait); 03009 //__COUT__ << states[i] << " => " << transName << __E__; 03010 03011 xmlOut.addTextElementToParent( 03012 "state_transition_name", transName, stateParent); 03013 transParameter = 03014 theStateMachine_.getTransitionParameter(states[i], *ait); 03015 //__COUT__ << states[i] << " => " << transParameter<< __E__; 03016 03017 xmlOut.addTextElementToParent( 03018 "state_transition_parameter", transParameter, stateParent); 03019 break; 03020 } 03021 } 03022 03023 // reset for 2nd pass 03024 it = trans.begin(); 03025 ait = actionNames.begin(); 03026 03027 // other states 03028 for(; it != trans.end() && ait != actionNames.end(); ++it, ++ait) 03029 { 03030 //__COUT__ << states[i] << " => " << it->second << __E__; 03031 03032 stateStr[0] = it->second; 03033 03034 if(stateStr[0] == 'R') 03035 continue; 03036 else if(stateStr[0] == 'C') 03037 continue; 03038 03039 xmlOut.addTextElementToParent( 03040 "state_transition", stateStr, stateParent); 03041 03042 //__COUT__ << states[i] << " => " << *ait << __E__; 03043 03044 xmlOut.addTextElementToParent( 03045 "state_transition_action", *ait, stateParent); 03046 03047 transName = theStateMachine_.getTransitionName(states[i], *ait); 03048 //__COUT__ << states[i] << " => " << transName << __E__; 03049 03050 xmlOut.addTextElementToParent( 03051 "state_transition_name", transName, stateParent); 03052 transParameter = 03053 theStateMachine_.getTransitionParameter(states[i], *ait); 03054 //__COUT__ << states[i] << " => " << transParameter<< __E__; 03055 03056 xmlOut.addTextElementToParent( 03057 "state_transition_parameter", transParameter, stateParent); 03058 } 03059 } 03060 } 03061 else if(requestType == "getStateMachineNames") 03062 { 03063 // get stateMachineAliasFilter if possible 03064 ConfigurationTree configLinkNode = 03065 CorePropertySupervisorBase::theConfigurationManager_ 03066 ->getSupervisorTableNode(supervisorContextUID_, 03067 supervisorApplicationUID_); 03068 03069 try 03070 { 03071 auto fsmNodes = 03072 configLinkNode.getNode("LinkToStateMachineTable").getChildren(); 03073 for(const auto& fsmNode : fsmNodes) 03074 xmlOut.addTextElementToData("stateMachineName", fsmNode.first); 03075 } 03076 catch(...) // else empty set of state machines.. can always choose "" 03077 { 03078 __COUT__ << "Caught exception, assuming no valid FSM names." << __E__; 03079 xmlOut.addTextElementToData("stateMachineName", ""); 03080 } 03081 } 03082 else if(requestType == "getIterationPlanStatus") 03083 { 03084 //__COUT__ << "checking it status" << __E__; 03085 theIterator_.handleCommandRequest(xmlOut, requestType, ""); 03086 } 03087 else if(requestType == "getCurrentState") 03088 { 03089 xmlOut.addTextElementToData("current_state", 03090 theStateMachine_.getCurrentStateName()); 03091 xmlOut.addTextElementToData("in_transition", 03092 theStateMachine_.isInTransition() ? "1" : "0"); 03093 if(theStateMachine_.isInTransition()) 03094 xmlOut.addTextElementToData( 03095 "transition_progress", 03096 RunControlStateMachine::theProgressBar_.readPercentageString()); 03097 else 03098 xmlOut.addTextElementToData("transition_progress", "100"); 03099 03100 char tmp[20]; 03101 sprintf(tmp, "%lu", theStateMachine_.getTimeInState()); 03102 xmlOut.addTextElementToData("time_in_state", tmp); 03103 03104 //__COUT__ << "current state: " << theStateMachine_.getCurrentStateName() << 03105 //__E__; 03106 03108 03109 std::string fsmName = CgiDataUtilities::getData(cgiIn, "fsmName"); 03110 // __COUT__ << "fsmName = " << fsmName << __E__; 03111 // __COUT__ << "activeStateMachineName_ = " << activeStateMachineName_ << 03112 //__E__; 03113 // __COUT__ << "theStateMachine_.getProvenanceStateName() = " << 03114 // theStateMachine_.getProvenanceStateName() << __E__; 03115 // __COUT__ << "theStateMachine_.getCurrentStateName() = " << 03116 // theStateMachine_.getCurrentStateName() << __E__; 03117 03118 if(!theStateMachine_.isInTransition()) 03119 { 03120 std::string stateMachineRunAlias = "Run"; // default to "Run" 03121 03122 // get stateMachineAliasFilter if possible 03123 ConfigurationTree configLinkNode = 03124 CorePropertySupervisorBase::theConfigurationManager_ 03125 ->getSupervisorTableNode(supervisorContextUID_, 03126 supervisorApplicationUID_); 03127 03128 if(!configLinkNode.isDisconnected()) 03129 { 03130 try // for backwards compatibility 03131 { 03132 ConfigurationTree fsmLinkNode = 03133 configLinkNode.getNode("LinkToStateMachineTable"); 03134 if(!fsmLinkNode.isDisconnected()) 03135 stateMachineRunAlias = 03136 fsmLinkNode.getNode(fsmName + "/RunDisplayAlias") 03137 .getValue<std::string>(); 03138 // else 03139 // __COUT_INFO__ << "FSM Link disconnected." << __E__; 03140 } 03141 catch(std::runtime_error& e) 03142 { 03143 //__COUT_INFO__ << e.what() << __E__; 03144 //__COUT_INFO__ << "No state machine Run alias. Ignoring and 03145 // assuming alias of '" << stateMachineRunAlias << ".'" << 03146 //__E__; 03147 } 03148 catch(...) 03149 { 03150 __COUT_ERR__ << "Unknown error. Should never happen." << __E__; 03151 03152 __COUT_INFO__ << "No state machine Run alias. Ignoring and " 03153 "assuming alias of '" 03154 << stateMachineRunAlias << ".'" << __E__; 03155 } 03156 } 03157 // else 03158 // __COUT_INFO__ << "FSM Link disconnected." << __E__; 03159 03160 //__COUT__ << "stateMachineRunAlias = " << stateMachineRunAlias << 03161 //__E__; 03162 03163 xmlOut.addTextElementToData("stateMachineRunAlias", stateMachineRunAlias); 03164 03166 03167 if(theStateMachine_.getCurrentStateName() == "Running" || 03168 theStateMachine_.getCurrentStateName() == "Paused") 03169 { 03170 sprintf(tmp, 03171 "Current %s Number: %u", 03172 stateMachineRunAlias.c_str(), 03173 getNextRunNumber(activeStateMachineName_) - 1); 03174 03175 if(RunControlStateMachine::asyncSoftFailureReceived_) 03176 { 03177 //__COUTV__(RunControlStateMachine::asyncSoftFailureReceived_); 03178 //__COUTV__(RunControlStateMachine::getErrorMessage()); 03179 xmlOut.addTextElementToData( 03180 "soft_error", RunControlStateMachine::getErrorMessage()); 03181 } 03182 } 03183 else 03184 sprintf(tmp, 03185 "Next %s Number: %u", 03186 stateMachineRunAlias.c_str(), 03187 getNextRunNumber(fsmName)); 03188 xmlOut.addTextElementToData("run_number", tmp); 03189 } 03190 } 03191 else if(requestType == "cancelStateMachineTransition") 03192 { 03193 __SS__ << "State transition was cancelled by user!" << __E__; 03194 __MCOUT__(ss.str()); 03195 RunControlStateMachine::theStateMachine_.setErrorMessage(ss.str()); 03196 RunControlStateMachine::asyncFailureReceived_ = true; 03197 } 03198 else if(requestType == "getErrorInStateMatchine") 03199 { 03200 xmlOut.addTextElementToData("FSM_Error", theStateMachine_.getErrorMessage()); 03201 } 03202 else if(requestType == "getDesktopIcons") 03203 { 03204 // get icons and create comma-separated string based on user permissions 03205 // note: each icon has own permission threshold, so each user can have 03206 // a unique desktop icon experience. 03207 03208 const DesktopIconTable* iconTable = 03209 CorePropertySupervisorBase::theConfigurationManager_->__GET_CONFIG__( 03210 DesktopIconTable); 03211 std::vector<DesktopIconTable::DesktopIcon> icons = 03212 iconTable->getAllDesktopIcons(); 03213 03214 std::string iconString = ""; // comma-separated icon string, 7 fields: 03215 // 0 - caption = text below icon 03216 // 1 - altText = text icon if no image given 03217 // 2 - uniqueWin = if true, only one window is allowed, 03218 // else multiple instances of window 3 - permissions = 03219 // security level needed to see icon 4 - picfn = 03220 // icon image filename 5 - linkurl = url of the window to 03221 // open 6 - folderPath = folder and subfolder location 03222 // '/' 03223 // separated for example: State 03224 // Machine,FSM,1,200,icon-Physics.gif,/WebPath/html/StateMachine.html?fsm_name=OtherRuns0,,Chat,CHAT,1,1,icon-Chat.png,/urn:xdaq-application:lid=250,,Visualizer,VIS,0,10,icon-Visualizer.png,/WebPath/html/Visualization.html?urn=270,,Configure,CFG,0,10,icon-Configure.png,/urn:xdaq-application:lid=281,,Front-ends,CFG,0,15,icon-Configure.png,/WebPath/html/ConfigurationGUI_subset.html?urn=281&subsetBasePath=FEInterfaceTable&groupingFieldList=Status%2CFEInterfacePluginName&recordAlias=Front%2Dends&editableFieldList=%21%2ACommentDescription%2C%21SlowControls%2A,Config 03225 // Subsets 03226 03227 //__COUTV__((unsigned int)userInfo.permissionLevel_); 03228 03229 std::map<std::string, WebUsers::permissionLevel_t> userPermissionLevelsMap = 03230 theWebUsers_.getPermissionsForUser(userInfo.uid_); 03231 std::map<std::string, WebUsers::permissionLevel_t> 03232 iconPermissionThresholdsMap; 03233 03234 bool firstIcon = true; 03235 for(const auto& icon : icons) 03236 { 03237 __COUTV__(icon.caption_); 03238 __COUTV__(icon.permissionThresholdString_); 03239 03240 CorePropertySupervisorBase::extractPermissionsMapFromString( 03241 icon.permissionThresholdString_, iconPermissionThresholdsMap); 03242 03243 if(!CorePropertySupervisorBase::doPermissionsGrantAccess( 03244 userPermissionLevelsMap, iconPermissionThresholdsMap)) 03245 continue; // skip icon if no access 03246 03247 //__COUTV__(icon.caption_); 03248 03249 // have icon access, so add to CSV string 03250 if(firstIcon) 03251 firstIcon = false; 03252 else 03253 iconString += ","; 03254 03255 iconString += icon.caption_; 03256 iconString += "," + icon.alternateText_; 03257 iconString += 03258 "," + std::string(icon.enforceOneWindowInstance_ ? "1" : "0"); 03259 iconString += 03260 "," + std::string("1"); // set permission to 1 so the 03261 // desktop shows every icon that the 03262 // server allows (i.e., trust server 03263 // security, ignore client security) 03264 iconString += "," + icon.imageURL_; 03265 iconString += "," + icon.windowContentURL_; 03266 iconString += "," + icon.folderPath_; 03267 } 03268 __COUTV__(iconString); 03269 03270 xmlOut.addTextElementToData("iconList", iconString); 03271 } 03272 else if(requestType == "gatewayLaunchOTS" || requestType == "gatewayLaunchWiz") 03273 { 03274 // NOTE: similar to ConfigurationGUI version but DOES keep active sessions 03275 03276 __COUT_WARN__ << requestType << " requestType received! " << __E__; 03277 __MOUT_WARN__ << requestType << " requestType received! " << __E__; 03278 03279 // gateway launch is different, in that it saves user sessions 03280 theWebUsers_.saveActiveSessions(); 03281 03282 // now launch 03283 03284 if(requestType == "gatewayLaunchOTS") 03285 GatewaySupervisor::launchStartOTSCommand( 03286 "LAUNCH_OTS", CorePropertySupervisorBase::theConfigurationManager_); 03287 else if(requestType == "gatewayLaunchWiz") 03288 GatewaySupervisor::launchStartOTSCommand( 03289 "LAUNCH_WIZ", CorePropertySupervisorBase::theConfigurationManager_); 03290 } 03291 else if(requestType == "resetUserTooltips") 03292 { 03293 WebUsers::resetAllUserTooltips(theWebUsers_.getUsersUsername(userInfo.uid_)); 03294 } 03295 else 03296 { 03297 __SS__ << "requestType Request, " << requestType << ", not recognized." 03298 << __E__; 03299 __SS_THROW__; 03300 } 03301 } 03302 catch(const std::runtime_error& e) 03303 { 03304 __SS__ << "An error was encountered handling requestType '" << requestType 03305 << "':" << e.what() << __E__; 03306 __COUT__ << "\n" << ss.str(); 03307 xmlOut.addTextElementToData("Error", ss.str()); 03308 } 03309 catch(...) 03310 { 03311 __SS__ << "An unknown error was encountered handling requestType '" << requestType 03312 << ".' " 03313 << "Please check the printouts to debug." << __E__; 03314 __COUT__ << "\n" << ss.str(); 03315 xmlOut.addTextElementToData("Error", ss.str()); 03316 } 03317 03318 // return xml doc holding server response 03319 xmlOut.outputXmlDocument( 03320 (std::ostringstream*)out, 03321 false /*dispStdOut*/, 03322 true /*allowWhiteSpace*/); // Note: allow white space need for error response 03323 03324 //__COUT__ << "Done" << __E__; 03325 } // end request() 03326 03327 //======================================================================================================================== 03328 // launchStartOTSCommand 03329 // static function (so WizardSupervisor can use it) 03330 // throws exception if command fails to start 03331 void GatewaySupervisor::launchStartOTSCommand(const std::string& command, 03332 ConfigurationManager* cfgMgr) 03333 { 03334 __COUT__ << "launch StartOTS Command = " << command << __E__; 03335 __COUT__ << "Extracting target context hostnames... " << __E__; 03336 03337 std::vector<std::string> hostnames; 03338 try 03339 { 03340 cfgMgr->init(); // completely reset to re-align with any changes 03341 03342 const XDAQContextTable* contextTable = cfgMgr->__GET_CONFIG__(XDAQContextTable); 03343 03344 auto contexts = contextTable->getContexts(); 03345 unsigned int i, j; 03346 for(const auto& context : contexts) 03347 { 03348 if(!context.status_) 03349 continue; 03350 03351 // find last slash 03352 j = 0; // default to whole string 03353 for(i = 0; i < context.address_.size(); ++i) 03354 if(context.address_[i] == '/') 03355 j = i + 1; 03356 hostnames.push_back(context.address_.substr(j)); 03357 __COUT__ << "StartOTS.sh hostname = " << hostnames.back() << __E__; 03358 } 03359 } 03360 catch(...) 03361 { 03362 __SS__ << "\nRelaunch of otsdaq interrupted! " 03363 << "The Configuration Manager could not be initialized." << __E__; 03364 03365 __SS_THROW__; 03366 } 03367 03368 for(const auto& hostname : hostnames) 03369 { 03370 std::string fn = (std::string(getenv("SERVICE_DATA_PATH")) + "/StartOTS_action_" + 03371 hostname + ".cmd"); 03372 FILE* fp = fopen(fn.c_str(), "w"); 03373 if(fp) 03374 { 03375 fprintf(fp, command.c_str()); 03376 fclose(fp); 03377 } 03378 else 03379 { 03380 __SS__ << "Unable to open command file: " << fn << __E__; 03381 __SS_THROW__; 03382 } 03383 } 03384 03385 sleep(2 /*seconds*/); // then verify that the commands were read 03386 // note: StartOTS.sh has a sleep of 1 second 03387 03388 for(const auto& hostname : hostnames) 03389 { 03390 std::string fn = (std::string(getenv("SERVICE_DATA_PATH")) + "/StartOTS_action_" + 03391 hostname + ".cmd"); 03392 FILE* fp = fopen(fn.c_str(), "r"); 03393 if(fp) 03394 { 03395 char line[100]; 03396 fgets(line, 100, fp); 03397 fclose(fp); 03398 03399 if(strcmp(line, command.c_str()) == 0) 03400 { 03401 __SS__ << "The command looks to have been ignored by " << hostname 03402 << ". Is StartOTS.sh still running on that node?" << __E__; 03403 __SS_THROW__; 03404 } 03405 __COUTV__(line); 03406 } 03407 else 03408 { 03409 __SS__ << "Unable to open command file for verification: " << fn << __E__; 03410 __SS_THROW__; 03411 } 03412 } 03413 } // end launchStartOTSCommand 03414 03415 //======================================================================================================================== 03416 // xoap::supervisorCookieCheck 03417 // verify cookie 03418 xoap::MessageReference GatewaySupervisor::supervisorCookieCheck( 03419 xoap::MessageReference message) 03420 03421 { 03422 //__COUT__ << __E__; 03423 03424 // SOAPUtilities::receive request parameters 03425 SOAPParameters parameters; 03426 parameters.addParameter("CookieCode"); 03427 parameters.addParameter("RefreshOption"); 03428 parameters.addParameter("IPAddress"); 03429 SOAPUtilities::receive(message, parameters); 03430 std::string cookieCode = parameters.getValue("CookieCode"); 03431 std::string refreshOption = 03432 parameters.getValue("RefreshOption"); // give external supervisors option to 03433 // refresh cookie or not, "1" to refresh 03434 std::string ipAddress = 03435 parameters.getValue("IPAddress"); // give external supervisors option to refresh 03436 // cookie or not, "1" to refresh 03437 03438 // If TRUE, cookie code is good, and refreshed code is in cookieCode, also pointers 03439 // optionally for uint8_t userPermissions, uint64_t uid Else, error message is 03440 // returned in cookieCode 03441 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t> 03442 userGroupPermissionsMap; 03443 std::string userWithLock = ""; 03444 uint64_t activeSessionIndex, uid; 03445 theWebUsers_.cookieCodeIsActiveForRequest(cookieCode, 03446 &userGroupPermissionsMap, 03447 &uid /*uid is not given to remote users*/, 03448 ipAddress, 03449 refreshOption == "1", 03450 &userWithLock, 03451 &activeSessionIndex); 03452 03453 //__COUT__ << "userWithLock " << userWithLock << __E__; 03454 03455 // fill return parameters 03456 SOAPParameters retParameters; 03457 retParameters.addParameter("CookieCode", cookieCode); 03458 retParameters.addParameter( 03459 "Permissions", StringMacros::mapToString(userGroupPermissionsMap).c_str()); 03460 retParameters.addParameter("UserWithLock", userWithLock); 03461 retParameters.addParameter("Username", theWebUsers_.getUsersUsername(uid)); 03462 retParameters.addParameter("DisplayName", theWebUsers_.getUsersDisplayName(uid)); 03463 sprintf(tmpStringForConversions_, "%lu", activeSessionIndex); 03464 retParameters.addParameter("ActiveSessionIndex", tmpStringForConversions_); 03465 03466 //__COUT__ << __E__; 03467 03468 return SOAPUtilities::makeSOAPMessageReference("CookieResponse", retParameters); 03469 } 03470 03471 //======================================================================================================================== 03472 // xoap::supervisorGetActiveUsers 03473 // get display names for all active users 03474 xoap::MessageReference GatewaySupervisor::supervisorGetActiveUsers( 03475 xoap::MessageReference message) 03476 03477 { 03478 __COUT__ << __E__; 03479 03480 SOAPParameters parameters("UserList", theWebUsers_.getActiveUsersString()); 03481 return SOAPUtilities::makeSOAPMessageReference("ActiveUserResponse", parameters); 03482 } 03483 03484 //======================================================================================================================== 03485 // xoap::supervisorSystemMessage 03486 // SOAPUtilities::receive a new system Message from a supervisor 03487 // ToUser wild card * is to all users 03488 xoap::MessageReference GatewaySupervisor::supervisorSystemMessage( 03489 xoap::MessageReference message) 03490 03491 { 03492 SOAPParameters parameters; 03493 parameters.addParameter("ToUser"); 03494 parameters.addParameter("Message"); 03495 SOAPUtilities::receive(message, parameters); 03496 03497 __COUT__ << "toUser: " << parameters.getValue("ToUser").substr(0, 10) 03498 << ", message: " << parameters.getValue("Message").substr(0, 10) << __E__; 03499 03500 theSystemMessenger_.addSystemMessage(parameters.getValue("ToUser"), 03501 parameters.getValue("Message")); 03502 return SOAPUtilities::makeSOAPMessageReference("SystemMessageResponse"); 03503 } 03504 03505 //=================================================================================================================== 03506 // xoap::supervisorSystemLogbookEntry 03507 // SOAPUtilities::receive a new system Message from a supervisor 03508 // ToUser wild card * is to all users 03509 xoap::MessageReference GatewaySupervisor::supervisorSystemLogbookEntry( 03510 xoap::MessageReference message) 03511 03512 { 03513 SOAPParameters parameters; 03514 parameters.addParameter("EntryText"); 03515 SOAPUtilities::receive(message, parameters); 03516 03517 __COUT__ << "EntryText: " << parameters.getValue("EntryText").substr(0, 10) << __E__; 03518 03519 makeSystemLogbookEntry(parameters.getValue("EntryText")); 03520 03521 return SOAPUtilities::makeSOAPMessageReference("SystemLogbookResponse"); 03522 } 03523 03524 //=================================================================================================================== 03525 // supervisorLastConfigGroupRequest 03526 // return the group name and key for the last state machine activity 03527 // 03528 // Note: same as OtsConfigurationWizardSupervisor::supervisorLastConfigGroupRequest 03529 xoap::MessageReference GatewaySupervisor::supervisorLastConfigGroupRequest( 03530 xoap::MessageReference message) 03531 03532 { 03533 SOAPParameters parameters; 03534 parameters.addParameter("ActionOfLastGroup"); 03535 SOAPUtilities::receive(message, parameters); 03536 03537 return GatewaySupervisor::lastConfigGroupRequestHandler(parameters); 03538 } 03539 03540 //=================================================================================================================== 03541 // xoap::lastConfigGroupRequestHandler 03542 // handles last config group request. 03543 // called by both: 03544 // GatewaySupervisor::supervisorLastConfigGroupRequest 03545 // OtsConfigurationWizardSupervisor::supervisorLastConfigGroupRequest 03546 xoap::MessageReference GatewaySupervisor::lastConfigGroupRequestHandler( 03547 const SOAPParameters& parameters) 03548 { 03549 std::string action = parameters.getValue("ActionOfLastGroup"); 03550 __COUT__ << "ActionOfLastGroup: " << action.substr(0, 10) << __E__; 03551 03552 std::string fileName = ""; 03553 if(action == "Configured") 03554 fileName = FSM_LAST_CONFIGURED_GROUP_ALIAS_FILE; 03555 else if(action == "Started") 03556 fileName = FSM_LAST_STARTED_GROUP_ALIAS_FILE; 03557 else 03558 { 03559 __COUT_ERR__ << "Invalid last group action requested." << __E__; 03560 return SOAPUtilities::makeSOAPMessageReference("LastConfigGroupResponseFailure"); 03561 } 03562 std::string timeString; 03563 std::pair<std::string /*group name*/, TableGroupKey> theGroup = 03564 loadGroupNameAndKey(fileName, timeString); 03565 03566 // fill return parameters 03567 SOAPParameters retParameters; 03568 retParameters.addParameter("GroupName", theGroup.first); 03569 retParameters.addParameter("GroupKey", theGroup.second.toString()); 03570 retParameters.addParameter("GroupAction", action); 03571 retParameters.addParameter("GroupActionTime", timeString); 03572 03573 return SOAPUtilities::makeSOAPMessageReference("LastConfigGroupResponse", 03574 retParameters); 03575 } 03576 03577 //======================================================================================================================== 03578 // getNextRunNumber 03579 // 03580 // If fsmName is passed, then get next run number for that FSM name 03581 // Else get next run number for the active FSM name, activeStateMachineName_ 03582 // 03583 // Note: the FSM name is sanitized of special characters and used in the filename. 03584 unsigned int GatewaySupervisor::getNextRunNumber(const std::string& fsmNameIn) 03585 { 03586 std::string runNumberFileName = RUN_NUMBER_PATH + "/"; 03587 std::string fsmName = fsmNameIn == "" ? activeStateMachineName_ : fsmNameIn; 03588 // prepend sanitized FSM name 03589 for(unsigned int i = 0; i < fsmName.size(); ++i) 03590 if((fsmName[i] >= 'a' && fsmName[i] <= 'z') || 03591 (fsmName[i] >= 'A' && fsmName[i] <= 'Z') || 03592 (fsmName[i] >= '0' && fsmName[i] <= '9')) 03593 runNumberFileName += fsmName[i]; 03594 runNumberFileName += RUN_NUMBER_FILE_NAME; 03595 //__COUT__ << "runNumberFileName: " << runNumberFileName << __E__; 03596 03597 std::ifstream runNumberFile(runNumberFileName.c_str()); 03598 if(!runNumberFile.is_open()) 03599 { 03600 __COUT__ << "Can't open file: " << runNumberFileName << __E__; 03601 03602 __COUT__ << "Creating file and setting Run Number to 1: " << runNumberFileName 03603 << __E__; 03604 FILE* fp = fopen(runNumberFileName.c_str(), "w"); 03605 fprintf(fp, "1"); 03606 fclose(fp); 03607 03608 runNumberFile.open(runNumberFileName.c_str()); 03609 if(!runNumberFile.is_open()) 03610 { 03611 __SS__ << "Error. Can't create file: " << runNumberFileName << __E__; 03612 __COUT_ERR__ << ss.str(); 03613 __SS_THROW__; 03614 } 03615 } 03616 std::string runNumberString; 03617 runNumberFile >> runNumberString; 03618 runNumberFile.close(); 03619 return atoi(runNumberString.c_str()); 03620 } 03621 03622 //======================================================================================================================== 03623 bool GatewaySupervisor::setNextRunNumber(unsigned int runNumber, 03624 const std::string& fsmNameIn) 03625 { 03626 std::string runNumberFileName = RUN_NUMBER_PATH + "/"; 03627 std::string fsmName = fsmNameIn == "" ? activeStateMachineName_ : fsmNameIn; 03628 // prepend sanitized FSM name 03629 for(unsigned int i = 0; i < fsmName.size(); ++i) 03630 if((fsmName[i] >= 'a' && fsmName[i] <= 'z') || 03631 (fsmName[i] >= 'A' && fsmName[i] <= 'Z') || 03632 (fsmName[i] >= '0' && fsmName[i] <= '9')) 03633 runNumberFileName += fsmName[i]; 03634 runNumberFileName += RUN_NUMBER_FILE_NAME; 03635 __COUT__ << "runNumberFileName: " << runNumberFileName << __E__; 03636 03637 std::ofstream runNumberFile(runNumberFileName.c_str()); 03638 if(!runNumberFile.is_open()) 03639 { 03640 __SS__ << "Can't open file: " << runNumberFileName << __E__; 03641 __COUT__ << ss.str(); 03642 __SS_THROW__; 03643 } 03644 std::stringstream runNumberStream; 03645 runNumberStream << runNumber; 03646 runNumberFile << runNumberStream.str().c_str(); 03647 runNumberFile.close(); 03648 return true; 03649 } 03650 03651 //======================================================================================================================== 03652 // loadGroupNameAndKey 03653 // loads group name and key (and time) from specified file 03654 // returns time string in returnedTimeString 03655 // 03656 // Note: this is static so the OtsConfigurationWizardSupervisor can call it 03657 std::pair<std::string /*group name*/, TableGroupKey> 03658 GatewaySupervisor::loadGroupNameAndKey(const std::string& fileName, 03659 std::string& returnedTimeString) 03660 { 03661 std::string fullPath = FSM_LAST_GROUP_ALIAS_PATH + "/" + fileName; 03662 03663 FILE* groupFile = fopen(fullPath.c_str(), "r"); 03664 if(!groupFile) 03665 { 03666 __COUT__ << "Can't open file: " << fullPath << __E__; 03667 03668 __COUT__ << "Returning empty groupName and key -1" << __E__; 03669 03670 return std::pair<std::string /*group name*/, TableGroupKey>("", TableGroupKey()); 03671 } 03672 03673 char line[500]; // assuming no group names longer than 500 chars 03674 // name and then key 03675 std::pair<std::string /*group name*/, TableGroupKey> theGroup; 03676 03677 fgets(line, 500, groupFile); // name 03678 theGroup.first = line; 03679 03680 fgets(line, 500, groupFile); // key 03681 int key; 03682 sscanf(line, "%d", &key); 03683 theGroup.second = key; 03684 03685 fgets(line, 500, groupFile); // time 03686 time_t timestamp; 03687 sscanf(line, "%ld", ×tamp); // type long int 03688 // struct tm tmstruct; 03689 // ::localtime_r(×tamp, &tmstruct); 03690 // ::strftime(line, 30, "%c %Z", &tmstruct); 03691 returnedTimeString = StringMacros::getTimestampString(timestamp); // line; 03692 fclose(groupFile); 03693 03694 __COUT__ << "theGroup.first= " << theGroup.first 03695 << " theGroup.second= " << theGroup.second << __E__; 03696 03697 return theGroup; 03698 } // end loadGroupNameAndKey() 03699 03700 //======================================================================================================================== 03701 void GatewaySupervisor::saveGroupNameAndKey( 03702 const std::pair<std::string /*group name*/, TableGroupKey>& theGroup, 03703 const std::string& fileName) 03704 { 03705 std::string fullPath = FSM_LAST_GROUP_ALIAS_PATH + "/" + fileName; 03706 03707 std::ofstream groupFile(fullPath.c_str()); 03708 if(!groupFile.is_open()) 03709 { 03710 __SS__ << "Error. Can't open file: " << fullPath << __E__; 03711 __COUT_ERR__ << "\n" << ss.str(); 03712 __SS_THROW__; 03713 } 03714 std::stringstream outss; 03715 outss << theGroup.first << "\n" << theGroup.second << "\n" << time(0); 03716 groupFile << outss.str().c_str(); 03717 groupFile.close(); 03718 } // end saveGroupNameAndKey() 03719 03721 03724 // void GatewaySupervisor::infoRequest(xgi::Input * in, xgi::Output * out ) 03725 //{ 03726 // __COUT__ << __LINE__ << __E__ << __E__; 03727 // cgicc::Cgicc cgi(in); 03728 // std::string Command=cgi.getElement("RequestType")->getValue(); 03729 // 03730 // if (Command=="FEWList") 03731 // { 03732 // *out << "<FEWList>" << __E__; 03733 // for (std::set<xdaq::ApplicationDescriptor*>::iterator 03734 // pxFESupervisorsIt=pxFESupervisors_.begin(); 03735 // pxFESupervisorsIt!=pxFESupervisors_.end(); pxFESupervisorsIt++) 03736 // { 03737 // *out << "<FEWInterface id='1' alias='FPIX Disk 1' type='OtsUDPHardware'>" << 03738 // __E__ 03739 // << "<svg xmlns='http://www.w3.org/2000/svg' version='1.1'>" << __E__ 03740 // << "<circle cx='100' cy='50' r='40' stroke='black' stroke-width='2' 03741 // fill='red' />" << __E__ 03742 // << "</svg>" << __E__ 03743 // << "</FEWInterface>" << __E__; 03744 // *out << "<FEWInterface id='2' alias='FPIX Disk 2' type='OtsUDPHardware'>" << 03745 // __E__ 03746 // << "<svg xmlns='http://www.w3.org/2000/svg' version='1.1'>" << __E__ 03747 // << "<circle cx='100' cy='50' r='40' stroke='black' stroke-width='2' 03748 // fill='red' />" << __E__ 03749 // << "</svg>" << __E__ 03750 // << "</FEWInterface>" << __E__; 03751 // } 03752 // *out << "</FEWList>" << __E__; 03753 // } 03754 //} 03755 //========================================================================================================================