00001 #include "otsdaq-core/WorkLoopManager/WorkLoopManager.h"
00002 #include "otsdaq-core/MessageFacility/MessageFacility.h"
00003 #include "otsdaq-core/Macros/CoutMacros.h"
00004 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
00005 #include "otsdaq-core/SOAPUtilities/SOAPCommand.h"
00006
00007 #include <toolbox/task/WorkLoopFactory.h>
00008
00009 #include <iostream>
00010 #include <sstream>
00011 #include <cstdlib>
00012 #include <cassert>
00013
00014
00015 using namespace ots;
00016
00017
00018 WorkLoopManager::WorkLoopManager(toolbox::task::ActionSignature* job) :
00019 cWorkLoopType_("waiting"),
00020 job_ (job),
00021 requestNumber_(0),
00022 requestName_ (job_->name())
00023 {
00024 __COUT__ << "Request name: " << requestName_ << " jobName: " << job_->name() << std::endl;
00025
00026 }
00027
00028
00029 WorkLoopManager::~WorkLoopManager(void)
00030 {}
00031
00032
00033 HttpXmlDocument WorkLoopManager::processRequest(cgicc::Cgicc& cgi)
00034 {
00035 return processRequest(composeWorkLoopName(requestNumber_++, cgi));
00036 }
00037
00038
00039 HttpXmlDocument WorkLoopManager::processRequest(const xoap::MessageReference& message)
00040 {
00041 return processRequest(composeWorkLoopName(requestNumber_++, message),&message);
00042 }
00043
00044
00045 HttpXmlDocument WorkLoopManager::processRequest(std::string workLoopName, const xoap::MessageReference* message)
00046 {
00047 HttpXmlDocument xmlDocument;
00048 std::stringstream requestNumberStream;
00049 RequestNumber requestNumber = getWorkLoopRequestNumber(workLoopName);
00050 requestNumberStream << requestNumber;
00051 std::stringstream reportStream;
00052
00053 __COUT__ << "Processing request! WorkLoops: " << workLoops_.size() << " req: " << requestNumber << std::endl;
00054 if(workLoops_.size() >= maxWorkLoops)
00055 {
00056 if(!removeTimedOutRequests())
00057 {
00058 reportStream << "Too many running requests (" << workLoops_.size() << "), try later!" << std::endl;
00059 __COUT__ << "ERROR: " << reportStream.str() << std::endl;
00060
00061 xmlDocument.addTextElementToData("RequestStatus", "ERROR");
00062 xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
00063 xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
00064 xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
00065 return xmlDocument;
00066 }
00067 }
00068 time(&(workLoops_[requestNumber].requestStartTime));
00069 workLoops_[requestNumber].requestLastTimeChecked = workLoops_[requestNumber].requestStartTime;
00070 workLoops_[requestNumber].request = getWorkLoopRequest(workLoopName);
00071 workLoops_[requestNumber].result = "EMPTY";
00072 workLoops_[requestNumber].progress = 0;
00073 workLoops_[requestNumber].done = false;
00074 workLoops_[requestNumber].workLoopName = workLoopName;
00075 if(message != 0)
00076 workLoops_[requestNumber].message = *message;
00077 try
00078 {
00079 workLoops_[requestNumber].workLoop = toolbox::task::getWorkLoopFactory()->getWorkLoop(workLoopName, cWorkLoopType_);
00080 }
00081 catch (xcept::Exception & e)
00082 {
00083 reportStream << "Can't create workloop, try again." << std::endl;
00084 __COUT__ << "ERROR: " << reportStream.str() << std::endl;
00085 xmlDocument.addTextElementToData("RequestStatus", "ERROR");
00086 xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
00087 xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
00088 xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
00089 removeWorkLoop(requestNumber);
00090 return xmlDocument;
00091 }
00092
00093 try
00094 {
00095 workLoops_[requestNumber].workLoop->submit(job_);
00096 }
00097 catch (xcept::Exception & e)
00098 {
00099 reportStream << "Can't submit workloop job, try again." << std::endl;
00100 __COUT__ << "ERROR: " << reportStream.str() << std::endl;
00101 xmlDocument.addTextElementToData("RequestStatus", "ERROR");
00102 xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
00103 xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
00104 xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
00105 removeWorkLoop(requestNumber);
00106 return xmlDocument;
00107 }
00108 try
00109 {
00110 workLoops_[requestNumber].workLoop->activate();
00111 }
00112 catch (xcept::Exception & e)
00113 {
00114 reportStream << "Can't activate workloop, try again." << std::endl;
00115 __COUT__ << "ERROR: " << reportStream.str() << std::endl;
00116 xmlDocument.addTextElementToData("RequestStatus", "ERROR");
00117 xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
00118 xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
00119 xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
00120 removeWorkLoop(requestNumber);
00121 return xmlDocument;
00122 }
00123
00124 __COUT__ << "SUCCESS: Request is being processed!" << std::endl;
00125
00126 xmlDocument.addTextElementToData("RequestStatus", "SUCCESS");
00127 xmlDocument.addTextElementToData("RequestName" , getWorkLoopRequest(workLoopName));
00128 xmlDocument.addTextElementToData("RequestNumber", requestNumberStream.str());
00129
00130 return xmlDocument;
00131 }
00132
00133
00134 bool WorkLoopManager::report(toolbox::task::WorkLoop* workLoop, std::string result, float progress, bool status)
00135 {
00136 RequestNumber requestNumber = getWorkLoopRequestNumber(workLoop);
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146 workLoops_[requestNumber].result = result;
00147 workLoops_[requestNumber].progress = progress;
00148 workLoops_[requestNumber].done = status;
00149 return true;
00150 }
00151
00152
00153 xoap::MessageReference WorkLoopManager::getMessage(toolbox::task::WorkLoop* workLoop)
00154 {
00155 RequestNumber requestNumber = getWorkLoopRequestNumber(workLoop);
00156 return workLoops_[requestNumber].message;
00157 }
00158
00159
00160 bool WorkLoopManager::getRequestResult(cgicc::Cgicc &cgi, HttpXmlDocument &xmlDocument)
00161 {
00162 std::stringstream reportStream;
00163 std::string requestNumberString = cgi.getElement("RequestNumber")->getValue();
00164 RequestNumber requestNumber = strtoull(requestNumberString.c_str(), 0 , 10);
00165
00166 __COUT__ << "Request: " << requestName_ << " RequestNumber=" << requestNumberString
00167 << " assigned # " << requestNumber << std::endl;
00168
00169 if(workLoops_.find(requestNumber) == workLoops_.end())
00170 {
00171 reportStream << "Can't find request " << requestNumber << " within the currently active " << workLoops_.size() << " requests!";
00172 __COUT__ << "WARNING: " << reportStream.str() << std::endl;
00173 xmlDocument.addTextElementToData("RequestStatus", "WARNING");
00174 xmlDocument.addTextElementToData("RequestName" , "Unknown");
00175 xmlDocument.addTextElementToData("RequestNumber", requestNumberString);
00176 xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
00177 return false;
00178 }
00179
00180 if(!workLoops_[requestNumber].done)
00181 {
00182 reportStream << "Still processing request " << requestNumber;
00183 __COUT__ << "WARNING: " << reportStream.str() << std::endl;
00184
00185 time(&(workLoops_[requestNumber].requestLastTimeChecked));
00186
00187 xmlDocument.addTextElementToData("RequestStatus" ,"MESSAGE");
00188 xmlDocument.addTextElementToData("RequestName" , workLoops_[requestNumber].request);
00189 xmlDocument.addTextElementToData("RequestNumber" , requestNumberString);
00190 xmlDocument.addTextElementToData("ErrorReport" , reportStream.str());
00191 std::stringstream progress;
00192 progress << workLoops_[requestNumber].progress;
00193 xmlDocument.addTextElementToData("RequestProgress", progress.str());
00194 return false;
00195 }
00196
00197
00198 xmlDocument.addTextElementToData("RequestStatus" , workLoops_[requestNumber].result);
00199 xmlDocument.addTextElementToData("RequestName" , workLoops_[requestNumber].request);
00200 xmlDocument.addTextElementToData("RequestNumber" , requestNumberString);
00201 std::stringstream progress;
00202 progress << workLoops_[requestNumber].progress;
00203 xmlDocument.addTextElementToData("RequestProgress", progress.str());
00204
00205 removeWorkLoop(requestNumber);
00206 return true;
00207 }
00208
00209
00210 bool WorkLoopManager::removeWorkLoop(toolbox::task::WorkLoop* workLoop)
00211 {
00212 return removeWorkLoop(getWorkLoopRequestNumber(workLoop));
00213 }
00214
00215
00216 bool WorkLoopManager::removeWorkLoop(RequestNumber requestNumber)
00217 {
00218 if(workLoops_.find(requestNumber) == workLoops_.end())
00219 {
00220 __COUT__ << "WorkLoop " << requestNumber << " is not in the WorkLoops list!" << std::endl;
00221 return false;
00222 }
00223
00224 if(workLoops_[requestNumber].workLoop == 0)
00225 {
00226 __COUT__ << "WorkLoop " << requestNumber << " was not created at all!" << std::endl;
00227 workLoops_.erase(requestNumber);
00228 return false;
00229 }
00230
00231 try
00232 {
00233 workLoops_[requestNumber].workLoop->cancel();
00234 }
00235 catch (xcept::Exception & e)
00236 {
00237 __COUT__ << "Can't cancel WorkLoop " << requestNumber << std::endl;
00238
00239 return false;
00240 }
00241 try
00242 {
00243 workLoops_[requestNumber].workLoop->remove(job_);
00244 }
00245 catch (xcept::Exception & e)
00246 {
00247
00248
00249
00250
00251
00252 }
00253 __COUT__ << "Deleting WorkLoop " << requestNumber << std::endl;
00254 toolbox::task::getWorkLoopFactory()->removeWorkLoop(workLoops_[requestNumber].workLoopName, cWorkLoopType_);
00255 workLoops_.erase(requestNumber);
00256 return true;
00257 }
00258
00259
00260 bool WorkLoopManager::removeProcessedRequests(void)
00261 {
00262 std::map<RequestNumber, WorkLoopStruct>::iterator it = workLoops_.begin();
00263 while(it != workLoops_.end())
00264 if(it->second.done)
00265 removeWorkLoop((it++)->first);
00266 else
00267 ++it;
00268 return true;
00269 }
00270
00271
00272 bool WorkLoopManager::removeTimedOutRequests(void)
00273 {
00274 time_t now;
00275 time(&now);
00276 std::map<RequestNumber, WorkLoopStruct>::iterator it = workLoops_.begin();
00277 __COUT__ << "Removing timed out " << std::endl;
00278 for( ; it != workLoops_.end(); it++)
00279 if(it->second.done && difftime(now,it->second.requestLastTimeChecked) > timeOutInSeconds)
00280 {
00281 __COUT__ << "Removing timed out request #" << it->first << " after " << difftime(now,it->second.requestLastTimeChecked) << " seconds." << std::endl;
00282 removeWorkLoop(it->first);
00283 return true;
00284 }
00285 __COUT__ << "Done Removing timed out " << std::endl;
00286 return false;
00287 }
00288
00289
00290
00291
00292
00293 std::string WorkLoopManager::composeWorkLoopName(RequestNumber requestNumber, cgicc::Cgicc &cgi)
00294 {
00295 std::stringstream name;
00296 name << requestNumber << "-" << cgi.getElement(requestName_)->getValue();
00297 __COUT__ << "Request: " << requestName_
00298 << " Value=" << cgi.getElement(requestName_)->getValue()
00299 << " WLName: " << name.str()
00300 << std::endl;
00301 return name.str();
00302 }
00303
00304
00305 std::string WorkLoopManager::composeWorkLoopName(RequestNumber requestNumber, const xoap::MessageReference& message)
00306 {
00307 SOAPCommand soapCommand(message);
00308 std::stringstream name;
00309 name << requestNumber << "-" << soapCommand.getCommand();
00310 __COUT__ << "Request: " << requestName_
00311 << " Value=" << soapCommand.getCommand()
00312 << " WLName: " << name.str()
00313 << std::endl;
00314 if(soapCommand.hasParameters())
00315 {
00316 name << '<';
00317 char separator = ',';
00318 for(SOAPParameters::const_iterator it=soapCommand.getParameters().begin(); it!=soapCommand.getParameters().end(); it++)
00319 {
00320 if(it != soapCommand.getParameters().begin())
00321 name << separator;
00322 name << it->first << "|" << it->second;
00323 }
00324 name << '>';
00325 }
00326 return name.str();
00327 }
00328
00329 //========================================================================================================================
00330 WorkLoopManager::RequestNumber WorkLoopManager::getWorkLoopRequestNumber(toolbox::task::WorkLoop* workLoop)
00331 {
00332 return getWorkLoopRequestNumber(workLoop->getName());
00333 }
00334
00335 //========================================================================================================================
00336 WorkLoopManager::RequestNumber WorkLoopManager::getWorkLoopRequestNumber(std::string workLoopName)
00337 {
00338 workLoopName = workLoopName.substr(0,workLoopName.find('-'));
00339 return strtoull(workLoopName.c_str(), 0 , 10);
00340 }
00341
00342 //========================================================================================================================
00343 std::string WorkLoopManager::getWorkLoopRequest(toolbox::task::WorkLoop* workLoop)
00344 {
00345 return getWorkLoopRequest(workLoop->getName());
00346 }
00347
00348 //========================================================================================================================
00349 std::string WorkLoopManager::getWorkLoopRequest(std::string workLoopName)
00350 {
00351 return workLoopName.substr(workLoopName.find('-')+1,workLoopName.find(std::string("/")+cWorkLoopType_)-workLoopName.find('-')-1);
00352 }
00353
00354 //========================================================================================================================
00355 void WorkLoopManager::translateWorkLoopName(toolbox::task::WorkLoop* workLoop, SOAPCommand& soapCommand)
00356 {
00357 std::string request = getWorkLoopRequest(workLoop);
00358 if(request.find('<') == std::string::npos)
00359 {
00360 __COUT__ << "Simple request" << std::endl;
00361 soapCommand.setCommand(request);
00362 }
00363 else
00364 {
00365 size_t ltPosition = request.find('<');
00366 size_t gtPosition = request.find('>');
00367 size_t begin = ltPosition+1;
00368 size_t orPosition;
00369 size_t commaPosition;
00370
00371 soapCommand.setCommand(request.substr(0,ltPosition));
00372 while((commaPosition = request.find(',',begin)) != std::string::npos)
00373 {
00374 orPosition = request.find('|',begin);
00375 soapCommand.setParameter(request.substr(begin,orPosition-begin),request.substr(orPosition+1,commaPosition-orPosition-1));
00376 begin = commaPosition+1;
00377 __COUT__ << "Comma: " << commaPosition << std::endl;
00378 }
00379 orPosition = request.find('|',begin);
00380 soapCommand.setParameter(request.substr(begin,orPosition-begin),request.substr(orPosition+1,gtPosition-orPosition-1));
00381 }
00382 __COUT__ << soapCommand << std::endl;
00383 //__COUT__ << name.substr(name.find(',')+1,name.find('/')-name.find(',')-1) << std::endl;
00384 }
00385