Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

JobCPath.cxx

Go to the documentation of this file.
00001 
00002 // $Id: JobCPath.cxx,v 1.65 2007/10/25 17:21:25 bckhouse Exp $
00003 //
00004 // A collection of modules linked together in the order they are to be
00005 // executed
00006 //
00007 // messier@huhepl.harvard.edu
00009 #include "JobControl/JobCPath.h"
00010 #include <cstring>  // strcmp
00011 #include <vector>
00012 #ifdef SITE_HAS_SIGC
00013 # include "sigc++/class_slot.h"
00014 #endif
00015 #include "MessageService/MsgService.h"
00016 #include "MessageService/MsgFormat.h"
00017 #include "MessageService/MsgTripWire.h"
00018 #include "JobControl/JobCEnv.h"
00019 #include "JobControl/JobCModuleRegistry.h"
00020 #include "JobControl/JobCModuleProxy.h"
00021 #include "JobControl/JobCRecord.h"
00022 #include "JobControl/JobCModule.h"
00023 #include "JobControl/JobCMethod.h"
00024 #include "JobControl/JobCommand.h"
00025 #include "JobControl/JobCInput.h"
00026 
00027 using namespace std;
00028 
00029 CVSID("$Id: JobCPath.cxx,v 1.65 2007/10/25 17:21:25 bckhouse Exp $");
00030 
00031 ClassImp(JobCPath)
00032 
00033 class JobCPathConnectionHelper
00034 {
00035 //======================================================================
00036 // A little helper class to make a list of paths connected to this one
00037 //======================================================================
00038 public:
00039   JobCPathConnectionHelper(const JobCPath* p) {
00040     this->BuildConnectionList(p);
00041     this->PreenConnectionList();
00042   }
00043   void BuildConnectionList(const JobCPath* p1) {
00044     // Recursively find all paths attached to p1
00045     fConnectionList.push_back(p1);
00046     for (int i=0; void *v=p1->GetAttached(i); ++i) {
00047       JobCPath *p2 = static_cast<JobCPath*>(v);
00048       this->BuildConnectionList(p2);
00049     }
00050   }
00051   void PreenConnectionList() {
00052     // Eliminate duplicates, keeping the deeper of the two occurances
00053     int size = fConnectionList.size();
00054     for (int i=0; i<size-1; ++i) {
00055       for (int j=i+1; j<size; ++j) {
00056         if (fConnectionList[i] == fConnectionList[j]) fConnectionList[i] = 0;
00057       }
00058     }
00059   }
00060   ostream& DoPrint(ostream& os) {
00061     // Print everyone in the list
00062     vector<const JobCPath*>::iterator itr(fConnectionList.begin());
00063     vector<const JobCPath*>::iterator itrEnd(fConnectionList.end());
00064     for (; itr!=itrEnd; ++itr) if (*itr) (*itr)->Print(os);
00065     return os;
00066   }
00067   void DoHandleResult(const JobCResult& r) {
00068     // Alert everyone in the list to the status change
00069     vector<const JobCPath*>::iterator itr(fConnectionList.begin());
00070     vector<const JobCPath*>::iterator itrEnd(fConnectionList.end());
00071     for (; itr!=itrEnd; ++itr) {
00072       if (*itr) (*itr)->HandleResult(r);
00073     }
00074   }
00075   void DoBeginJob() {
00076     // Alert everyone in the list to the start of job
00077     vector<const JobCPath*>::iterator itr(fConnectionList.begin());
00078     vector<const JobCPath*>::iterator itrEnd(fConnectionList.end());
00079     for (; itr!=itrEnd; ++itr) {
00080       if (*itr) (*itr)->BeginJob();
00081     }
00082   }
00083   void SetRefreshMode(bool m) {
00084     // Alert everyone in the list that we're running in refresh mode
00085     vector<const JobCPath*>::iterator itr(fConnectionList.begin());
00086     vector<const JobCPath*>::iterator itrEnd(fConnectionList.end());
00087     for (; itr!=itrEnd; ++itr) {
00088       if (*itr) (*itr)->SetRefreshMode(m);
00089     }
00090   }
00091 private:
00092   vector<const JobCPath*> fConnectionList; // List of job paths connected
00093 };
00094 
00095 //......................................................................
00096 
00097 void JobCPath::Print(ostream& os) const
00098 {
00099 //======================================================================
00100 // Print the job path to the MsgStream os
00101 //======================================================================
00102   os << fName.c_str()
00103      << "("
00104      << fNin   << " in "
00105      << fNpass << " out "
00106      << fNfail << " filt.)\n";
00107   int i=0;
00108   MsgFormat i1("%3d");
00109   list<JobCNode*>::const_iterator      itrEnd      = fNodeList.end();
00110   for (list<JobCNode*>::const_iterator itrJobCNode = fNodeList.begin();
00111        itrJobCNode != itrEnd;
00112        ++itrJobCNode) {
00113     os << i1(++i) << ") " << (**itrJobCNode) << "\n";
00114   }
00115 
00116   // Print list of paths attached to this one
00117   bool haveconnect = false;
00118   const JobCGraphVtx* v = 0;
00119   for (i=0; (v=this->GetAttached(i))!=0; ++i) {
00120     const JobCPath* p2 = dynamic_cast<const JobCPath*>(v);
00121     if (p2!=0 && haveconnect==false) {
00122       os << "  |-->";
00123     }
00124     os << "/" << p2->GetName();
00125     haveconnect = true;
00126   }
00127   if (haveconnect) os << "/\n";
00128 }
00129 
00130 //......................................................................
00131 
00132 ostream& operator<<(ostream& os, const JobCPath& p)
00133 {
00134   JobCPathConnectionHelper jcpph(&p);
00135   return jcpph.DoPrint(os);
00136 }
00137 
00138 //......................................................................
00139 
00140 JobCPath::JobCPath() :
00141   fIsRefreshRun(false),
00142   fAtJobStart(true),
00143   fName(""),
00144   fNin(0),
00145   fNpass(0),
00146   fNfail(0),
00147   fMom(0),
00148   fInput(0),
00149   fDummyModule(0),
00150   fDummyNode(0)
00151 {
00152     MSG("JobC", Msg::kDebug) << " default constructor\n";
00153     //cerr << "JobCPath::JobCPath()\n";
00154 }
00155 
00156 //......................................................................
00157 
00158 JobCPath::JobCPath(const char*      name,
00159                    MomNavigator*    mom,
00160                    JobCInputModule* inp) :
00161   fIsRefreshRun(false),
00162   fAtJobStart(true),
00163   fName(name),
00164   fNin(0),
00165   fNpass(0),
00166   fNfail(0),
00167   fMom(mom),
00168   fInput(inp),
00169   fDummyModule(0),
00170   fDummyNode(0)
00171 {
00172 //======================================================================
00173 // Purpose: Create and empty, named path which lives in the job
00174 //          environment "env"
00175 // Input  : name - the name of this path
00176 //        : env  - pointer to the job environment data
00177 //======================================================================
00178 
00179     MSG("JobC", Msg::kDebug) << " input module at " << (void*)inp << endl;
00180     //cerr << "JobCPath::JobCPath(\""<<name<<"\","<<(void*)mom<<","<<(void*)inp<<")\n";
00181 }
00182 
00183 //......................................................................
00184 
00185 JobCPath::~JobCPath()
00186 {
00187 //======================================================================
00188 // Purpose: Delete a path
00189 //======================================================================
00190   MSG("JobC", Msg::kVerbose) << this->GetName() << " destructor" << "\n";
00191 
00192 #ifdef SITE_HAS_SIGC
00193   this->SigDelete(this);
00194 #endif
00195 
00196   // Delete the nodes attached to this path
00197   list<JobCNode*>::iterator itrJobCNode;
00198   for (itrJobCNode = fNodeList.begin();
00199        itrJobCNode != fNodeList.end();
00200        ++itrJobCNode) {
00201     MSG("JobC", Msg::kVerbose) <<
00202       " >delete node " << (**itrJobCNode) << "\n";
00203     delete (*itrJobCNode);
00204   }
00205 
00206   // Delete modules attached to this path
00207   list<JobCModule*>::iterator itrJobCModule;
00208   for (itrJobCModule  = fModuleList.begin();
00209        itrJobCModule != fModuleList.end();
00210        ++itrJobCModule) {
00211     MSG("JobC", Msg::kVerbose) <<
00212       " >delete module " << (*itrJobCModule)->GetName() << "\n";
00213 
00214     // Tell the module the job is over before deleting it
00215     (*itrJobCModule)->EndJob();
00216 
00217     delete (*itrJobCModule);
00218   }
00219 
00220   if (fDummyModule) { delete fDummyModule; fDummyModule = 0; }
00221   if (fDummyNode)   { delete fDummyNode;   fDummyNode   = 0; }
00222 }
00223 
00224 //......................................................................
00225 
00226 #ifdef SITE_HAS_SIGC
00227 void JobCPath::NodeUpdateCB(JobCNode* /*n*/, JobCNode::Update_t u)
00228 {
00229 //======================================================================
00230 // Provide a call-back to handle node reconfiguration
00231 //======================================================================
00232   switch (u) {
00233   case JobCNode::kFilter: this->SigUpdate(this,JobCPath::kFilters);
00234   default:                this->SigUpdate(this,JobCPath::kGeneral);
00235   }
00236 }
00237 #endif
00238 
00239 //......................................................................
00240 
00241 bool JobCPath::AtJobStart() const
00242 {
00243 //======================================================================
00244 // Are we starting a new job?
00245 //======================================================================
00246   bool tmp = fAtJobStart;
00247   fAtJobStart = false;
00248   return tmp;
00249 }
00250 
00251 //......................................................................
00252 
00253 void JobCPath::CheckResult(const JobCResult& r)
00254 {
00255 //======================================================================
00256 // Purpose: Check the result of a node to see if the path needs to
00257 //          emit any status changes
00258 //======================================================================
00259   // Check conditions that require a response
00260     MSG("JobC", Msg::kVerbose) << "CheckResult: Current result is " << r << endl;
00261 
00262   if ( r.BeginFile() || r.EndFile() || r.BeginRun()  || r.EndRun() ) {
00263     this->PropagateResult(r,this);
00264   }
00265 }
00266 
00267 //......................................................................
00268 
00269 void JobCPath::HandleResult(const JobCResult& r) const
00270 {
00271 //======================================================================
00272 // Purpose: Check the result of a node to see if the path needs to
00273 //          emit any status changes
00274 //======================================================================
00275     MSG("JobC", Msg::kVerbose) << "HandleResult: Current result is " << r << endl;
00276 
00277   bool beginFile = r.BeginFile();
00278   bool endFile   = r.EndFile();
00279   bool beginRun  = r.BeginRun();
00280   bool endRun    = r.EndRun();
00281 
00282   list<JobCModule*>::const_iterator itrJobCModule;
00283   for (itrJobCModule  = fModuleList.begin();
00284        itrJobCModule != fModuleList.end();
00285        ++itrJobCModule) {
00286     if (endFile)   { (*itrJobCModule)->EndFile();   }
00287     if (endRun)    { (*itrJobCModule)->EndRun();    }
00288     if (beginRun)  { (*itrJobCModule)->BeginRun();  }
00289     if (beginFile) { (*itrJobCModule)->BeginFile(); }
00290   }
00291 }
00292 
00293 //......................................................................
00294 
00295 void JobCPath::PropagateResult(const JobCResult& r, JobCPath* p)
00296 {
00297 //======================================================================
00298 // Send the result r to all the paths attached to path p
00299 //======================================================================
00300   // Use the print helper to get the list of attached paths
00301   JobCPathConnectionHelper h(p);
00302   h.DoHandleResult(r);
00303 }
00304 
00305 //......................................................................
00306 
00307 const char* JobCPath::GetName() const { return fName.c_str(); }
00308 
00309 //......................................................................
00310 
00311 JobCModule *JobCPath::GetModule(const char *moduleName, bool create)
00312 {
00313 //======================================================================
00314 // Get the module named "moduleName" in this path. If no module is
00315 // found then the method returns 0 if create==false. If create==true
00316 // the a module with the given name is created and a pointer to it
00317 // returned.
00318 //======================================================================
00319   list<JobCModule*>::iterator itrJobCModule(fModuleList.begin());
00320   list<JobCModule*>::iterator itrEnd(fModuleList.end());
00321   for (;itrJobCModule != itrEnd; ++itrJobCModule) {
00322     if (strcmp(moduleName,(*itrJobCModule)->GetName())==0) {
00323       MSG("JobC",Msg::kVerbose) <<
00324         "Found " << moduleName << " in path " << fName << "\n";
00325       return (*itrJobCModule);
00326     }
00327   }
00328   // Failed to find the module. Either return 0 or build the module
00329   if (create == false) return 0;
00330 
00331   // Not found and we've been asked to make one.
00332   JobCModuleProxy*
00333     jmp = JobCModuleRegistry::Instance().LookUp(moduleName);
00334   if (jmp) {
00335     JobCModule* m = jmp->CreateModule(); // Remember to delete this!
00336     m->SetPath(this);
00337     fModuleList.push_back(m);            // Add to path's modules
00338     return m;
00339   }
00340 
00341   // Errors fall through to here
00342   return 0;
00343 }
00344 
00345 //......................................................................
00346 
00347 JobCNode* JobCPath::FindNode(const char* module, const char* method)
00348 {
00349 //======================================================================
00350 // Purpose: Look for a node which matches the module method pair
00351 //======================================================================
00352   list<JobCNode*>::const_iterator itr(fNodeList.begin());
00353   list<JobCNode*>::const_iterator itrEnd(fNodeList.end());
00354   for (; itr!=itrEnd; ++itr) {
00355     if ((*itr)->MatchModuleMethod(module,method)) {
00356       return (*itr);
00357     }
00358   }
00359   return 0;
00360 }
00361 
00362 JobCInputModule* JobCPath::GetInputModule()
00363 {
00364     return fInput;
00365 }
00366 
00367 
00368 //......................................................................
00369 
00370 bool JobCPath::HandleError(const JobCResult& result, const JobCNode* n)
00371 {
00372 //======================================================================
00373 // Purpose: Handle any errors that might have occured from executing a
00374 // node
00375 //
00376 // Returns: true  - stop the run
00377 //          false - continue the run
00378 //======================================================================
00379   JobCResult::Error_t errlvl = result.ErrorLevel();
00380   if (errlvl == JobCResult::kWarning) {
00381 //    MSG("JobC",Msg::kWarning) << "Warning in: [" << (*n) << "]\n";
00382   }
00383   else if (errlvl == JobCResult::kError) {
00384     MSG("JobC",Msg::kError) << "Error in: [" << (*n) << "]\n";
00385   }
00386   else {
00387     MSG("JobC",Msg::kFatal) <<
00388       "Fatal error in: [" << (*n) << "]\n";
00389   }
00390 
00391   // Is error relatively mild?
00392   JobCResult::Error_t errorThreshold = JobCResult::kError;
00393   if (errlvl < errorThreshold) return false; // Keep rolling...
00394 
00395   // Is the erro fatal?
00396   if (errlvl == JobCResult::kFatal) abort();
00397 
00398   return true; // Stop the run
00399 }
00400 
00401 //......................................................................
00402 
00403 JobCModule& JobCPath::Mod(const char* moduleName)
00404 {
00405 //======================================================================
00406 // Return the module in this path by name. If not found return a dummy
00407 // module. This method is intened for use interactively so it doesn't
00408 // use pointers. Ie. it tries to help prevent people from doing
00409 // (JobCModule*)0->Method(); which would trash their root session
00410 //======================================================================
00411   JobCModule* m = this->GetModule(moduleName, false);
00412   if (m) { return (*m); }
00413 
00414   MSG("JobC",Msg::kWarning) <<
00415     "Path '" << this->GetName() << "' " <<
00416     "does not contain module '" << moduleName << "'.\n";
00417 
00418   // In this case return a dummy, empty module to avoid having things
00419   // complete blow up in the user's face...
00420   if (fDummyModule == 0) fDummyModule = new JobCModule;
00421   return (*fDummyModule);
00422 }
00423 
00424 //......................................................................
00425 
00426 JobCNode& JobCPath::Node(const char* nodeName)
00427 {
00428 //======================================================================
00429 // Return the module in this path by name. If not found return a dummy
00430 // module. This method is intened for use interactively so it doesn't
00431 // use pointers. Ie. it tries to help prevent people from doing
00432 // (JobCModule*)0->Method(); which would trash their root session
00433 //======================================================================
00434   std::string module;
00435   std::string method;
00436   JobCommand::SplitLine(nodeName,':',module,method);
00437 
00438   JobCNode* n = this->FindNode(module.c_str(),method.c_str());
00439   if (n) { return (*n); }
00440 
00441   MSG("JobC",Msg::kWarning) <<
00442     "Path '" << this->GetName() << "' " <<
00443     "does contain node '" << nodeName << "'.\n";
00444 
00445   // In this case return a dummy, empty module to avoid having things
00446   // complete blow up in the user's face...
00447   if (fDummyNode == 0) fDummyNode = new JobCNode;
00448   return (*fDummyNode);
00449 }
00450 
00451 //......................................................................
00452 
00453 JobCNode* JobCPath::CreateNode(const char* modName, const char* metName)
00454 {
00455 //======================================================================
00456 // Purpose: Create a node using a specified module and method
00457 //
00458 // Inputs: modName - name of the module to use
00459 //         metName - name of the method to use
00460 //
00461 // Returns: Pointer to the node created
00462 //======================================================================
00463   // Look the module up
00464   JobCModule *module = this->GetModule(modName, true);
00465   if (module == 0) {
00466     MSG("JobC",Msg::kWarning) <<
00467       "Get failed for module '" << modName << "'.\n";
00468     return 0;
00469   }
00470 
00471   // Get the method
00472   const JobCMethod* method = JobCMethod::GetMethodByName(metName);
00473   if (method == 0) {
00474     MSG("JobC",Msg::kWarning) <<
00475       "Look up failed for method '" << metName << "'\n";
00476     return 0;
00477   }
00478   MSG("JobC", Msg::kDebug) << "Created node "
00479                            << module->GetName() << "::"
00480                            << method->GetName() << "\n";
00481 
00482   // Create the node
00483   JobCNode* n = new JobCNode(module, method);
00484 #ifdef SITE_HAS_SIGC
00485   if (n) {
00486     // Attach the Filter update signal to the node's filter update signal
00487     n->SigUpdate.connect(SigC::slot_class(*this,&JobCPath::NodeUpdateCB));
00488   }
00489 #endif
00490   return n;
00491 }
00492 
00493 //......................................................................
00494 
00495 void JobCPath::SetAllFilters(bool onOff)
00496 {
00497 //======================================================================
00498 // Purpose: Set all nodes to filter (true) or not to filter (false)
00499 //======================================================================
00500   list<JobCNode*>::iterator itr(fNodeList.begin());
00501   list<JobCNode*>::iterator itrEnd(fNodeList.end());
00502   for (; itr!=itrEnd; ++itr) {
00503     if (onOff) {
00504       (*itr)->FilterOn();
00505     }
00506     else {
00507       (*itr)->FilterOff();
00508     }
00509   }
00510 }
00511 
00512 //......................................................................
00513 
00514 void JobCPath::ReverseAllFilters()
00515 {
00516 //======================================================================
00517 // Purpose: Reverse the meaning of pass/fail for all active filters
00518 //======================================================================
00519   list<JobCNode*>::iterator itr(fNodeList.begin());
00520   list<JobCNode*>::iterator itrEnd(fNodeList.end());
00521   for (; itr!=itrEnd; ++itr) {
00522     (*itr)->ReverseFilter();
00523   }
00524 }
00525 
00526 //......................................................................
00527 
00528 JobCNode* JobCPath::PushFront(const char *moduleName, const char *methodName)
00529 {
00530 //======================================================================
00531 // Purpose: Add a module::method pair to the begining of the path
00532 //
00533 // Inputs: moduleName - name of the module
00534 //         methodName - name of the method
00535 //
00536 // Returns: pointer to node created
00537 //======================================================================
00538   // Create a node
00539   JobCNode *node = this->CreateNode(moduleName, methodName);
00540 
00541   // Add the node to the front of the list
00542   if (node) {
00543     fNodeList.push_front(node);
00544 #ifdef SITE_HAS_SIGC
00545     this->SigUpdate(this,JobCPath::kAddNode);
00546 #endif
00547   }
00548   return node;
00549 }
00550 
00551 //......................................................................
00552 
00553 JobCNode* JobCPath::PushBack(const char *moduleName, const char *methodName)
00554 {
00555 //======================================================================
00556 // Purpose: Add a module::method pair to the end of the path
00557 //
00558 // Inputs: moduleName - name of the module
00559 //         methodName - name of the method
00560 //
00561 // Returns: pointer to the node created
00562 //======================================================================
00563   // Create a node
00564   JobCNode *node = this->CreateNode(moduleName, methodName);
00565   if (node == 0) {
00566     MSG("JobC", Msg::kWarning)
00567       << "Failed to create node "
00568       << moduleName << "::" << methodName << "\n";
00569     return 0;
00570   }
00571 
00572   // Add the node to the front of the list
00573   if (node) {
00574     fNodeList.push_back(node);
00575 #ifdef SITE_HAS_SIGC
00576     this->SigUpdate(this,JobCPath::kAddNode);
00577 #endif
00578   }
00579   return node;
00580 }
00581 
00582 //......................................................................
00583 
00584 JobCNode* JobCPath::AddAt(const char *moduleName,
00585                           const char *methodName, int n)
00586 {
00587 //======================================================================
00588 // Purpose: Add a module::method pair at the nth position in the path
00589 //
00590 // Inputs: moduleName - name of the module
00591 //         methodName - name of the method
00592 //
00593 // Returns: pointer to node created
00594 //======================================================================
00595   // Create the node
00596   JobCNode *node = this->CreateNode(moduleName, methodName);
00597 
00598   // Advance to this place in the list. Note: start at 1 since that's
00599   // the way humans count. Ie. n=1 places the node first in the list,
00600   // n=2 second in the list etc.
00601   list<JobCNode*>::iterator itrJobCNode = fNodeList.begin();
00602   for (int i=1; i<n; ++i) {
00603     if (++itrJobCNode == fNodeList.end()) break;
00604   }
00605 
00606   // Insert at this point
00607   if (node) {
00608     fNodeList.insert(itrJobCNode, node);
00609 #ifdef SITE_HAS_SIGC
00610     this->SigUpdate(this,JobCPath::kAddNode);
00611 #endif
00612   }
00613 
00614   return node;
00615 }
00616 
00617 //......................................................................
00618 
00619 JobCNode* JobCPath::AddBetween(const char *moduleName,
00620                                const char *methodName,
00621                                const char *afterNodeName,
00622                                const char *beforeNodeName)
00623 {
00624 //======================================================================
00625 // Purpose: Add a module::method pair to the path between named modules
00626 //
00627 // Inputs: moduleName     - name of the module
00628 //         methodName     - name of the method
00629 //         afterNodeName  - name of the node to insert after
00630 //         beforeNodeName - name of the node to insert before
00631 //
00632 // Returns: pointer to node created
00633 //======================================================================
00634   // Create the node.
00635   JobCNode* newNode = this->CreateNode(moduleName, methodName);
00636 
00637   if(!newNode){
00638     MSG("JobCPath", Msg::kFatal) << "Could not create node "
00639                                  << moduleName << ":" << methodName << endl;
00640     return 0;
00641   }
00642 
00643   // Find the node we have to insert after.
00644   std::string afterModule, afterMethod;
00645   JobCommand::SplitLine(afterNodeName, ':', afterModule, afterMethod);
00646   JobCNode* afterNode = this->FindNode(afterModule.c_str() ,afterMethod.c_str());
00647 
00648   // Find the node we have to insert before.
00649   std::string beforeModule, beforeMethod;
00650   JobCommand::SplitLine(beforeNodeName, ':', beforeModule, beforeMethod);
00651   JobCNode* beforeNode = this->FindNode(beforeModule.c_str() ,beforeMethod.c_str());
00652 
00653   if(!afterNode){
00654     MSG("JobCPath", Msg::kFatal) << "Could not find node "
00655                                  << afterNodeName << endl;
00656     return 0;
00657   }
00658   if(!beforeNode){
00659     MSG("JobCPath", Msg::kFatal) << "Could not find node "
00660                                  << beforeNodeName << endl;
00661     return 0;
00662   }
00663 
00664   list<JobCNode*>::iterator it = fNodeList.begin();
00665 
00666   for(; it != fNodeList.end(); ++it){
00667     if(*it == afterNode){ // We found the node to go after.
00668       // Find the node we will be before.
00669       ++it;
00670       // Check it's the one we ought to be before.
00671       if(it != fNodeList.end() && *it == beforeNode){
00672         fNodeList.insert(it, newNode);
00673 #ifdef SITE_HAS_SIGC
00674         this->SigUpdate(this, JobCPath::kAddNode);
00675 #endif
00676         return newNode;
00677       }
00678       else{
00679         MSG("JobCPath", Msg::kFatal) << afterNodeName
00680                                      << " and "
00681                                      << beforeNodeName
00682                                      << " are not adjacent\n";
00683         return 0;
00684       }
00685     }
00686   }
00687 
00688   MSG("JobCPath", Msg::kFatal) << "This should never happen.\n";
00689   return 0;
00690 }
00691 
00692 //......................................................................
00693 
00694 void JobCPath::Remove(const char *moduleName, const char *methodName)
00695 {
00696 //======================================================================
00697 // Purpose: Remove a module::method pair from the path
00698 //
00699 // Inputs: moduleName - name of the module
00700 //         methodName - name of the method
00701 //======================================================================
00702   // Find the node coresponding to this module/method
00703   bool haveMatch = false; // Is there a node that matches
00704   list<JobCNode*>::iterator itrJobCNode(fNodeList.begin());
00705   list<JobCNode*>::iterator itrEnd(fNodeList.end());
00706   for (;itrJobCNode != itrEnd; ++itrJobCNode) {
00707     if ( (haveMatch =
00708           (*itrJobCNode)->MatchModuleMethod(moduleName, methodName))) {
00709       break;
00710     }
00711   }
00712 
00713   if (haveMatch) {
00714     // Delete the node object pointed to
00715     delete (*itrJobCNode);
00716 
00717     // Remove pointer from list
00718     fNodeList.erase(itrJobCNode);
00719 #ifdef SITE_HAS_SIGC
00720     this->SigUpdate(this,JobCPath::kRemoveNode);
00721 #endif
00722     return;
00723   }
00724 
00725   // No match in list
00726   MSG("JobC", Msg::kWarning)
00727     << "Path does not contain "
00728     << moduleName << "::" << methodName << ".\n";
00729 }
00730 
00731 //......................................................................
00732 
00733 bool JobCPath::EvalInput(JobCRecord* rec)
00734 {
00735 //======================================================================
00736 // Evaluate this node in the graph
00737 //======================================================================
00738   // Get the result of running this path
00739   JobCResult result = this->Execute(rec);
00740   MSG("JobC", Msg::kVerbose) << "EvalInput gets result = " << result << endl;
00741 
00742 
00743 
00744   // Decide if execute was sucessful or not
00745   if ( result.EndOfInputStream() || result.Failed() ) return false;
00746   return true;
00747 }
00748 
00749 //......................................................................
00750 
00751 void JobCPath::Attach(JobCGraphVtx *p)
00752 {
00753 //======================================================================
00754 // Attach a path to this one
00755 //======================================================================
00756   this->JobCGraphVtx::Attach(p);
00757 #ifdef SITE_HAS_SIGC
00758   this->SigUpdate(this,JobCPath::kAddConnection);
00759 #endif
00760 }
00761 
00762 //......................................................................
00763 
00764 void JobCPath::Detach(JobCGraphVtx *p)
00765 {
00766 //======================================================================
00767 // Attach a path to this one
00768 //======================================================================
00769   this->JobCGraphVtx::Detach(p);
00770 #ifdef SITE_HAS_SIGC
00771   this->SigUpdate(this,JobCPath::kRemoveConnection);
00772 #endif
00773 }
00774 
00775 //......................................................................
00776 
00777 JobCResult JobCPath::Execute(JobCRecord* rec)
00778 {
00779 //======================================================================
00780 // Purpose: Run a record through every node in the path
00781 //
00782 // Inputs: rec - the MINOS Object Map that holds the data to process
00783 //
00784 // Returns: Pass/Fail depending on whether the record passed every node
00785 //======================================================================
00786 
00787   // Count events processed
00788   ++fNin;
00789 
00790   // Loop over all nodes in path
00791   list<JobCNode*>::iterator itrJobCNode(fNodeList.begin());
00792   list<JobCNode*>::iterator itrEnd(fNodeList.end());
00793   for (;itrJobCNode != itrEnd; ++itrJobCNode) {
00794 
00795     // We'll need to make some querries about what kind of node this
00796     // is, so get the method type
00797     JobCMethod m = (*itrJobCNode)->GetMethod();
00798 
00799     // Don't evalute Get methods on "refresh" runs
00800     // This makes sense in the "old" framework (hence the fInput=0
00801     if (fInput==0 && (fIsRefreshRun == true) && (m == JobCMethod::kGet)) {
00802       continue;
00803     }
00804 
00805     // Evaluate this node
00806     MsgTripWire::Instance().StartNode(); //Record start of node
00807     fResult = (*itrJobCNode)->Execute(rec->GetDataPtr());
00808     MSG("JobC", Msg::kVerbose) << "Result of node " << *(*itrJobCNode) << "execution is: " << fResult << endl;
00809 
00810 
00811     // See if the job module produced any errors, warnings, or other
00812     // conditions which require special handling
00813     if (fResult.HaveError()) {
00814       bool stopRun = this->HandleError(fResult,(*itrJobCNode));
00815       if (stopRun) return fResult;
00816     }
00817 
00818     // On end of input we have to adjust the counter since the stream
00819     // failed to deliver a new record
00820     if ( fResult.EndOfInputStream() ) {
00821       --fNin;
00822       return fResult;
00823     }
00824 
00825     // See if record was labeled non-phyiscs
00826     if ( fResult.NonPhysicsRecord() ) rec->SetIsPhysics(false);
00827 
00828     // See if this result has triggered any status changes
00829     this->CheckResult(fResult);
00830 
00831     // Exit on failure
00832     if (fResult.Failed()) {
00833       ++fNfail;
00834       return fResult;
00835     }
00836   } // loop on nodes
00837 
00838   // Passed all nodes
00839   ++fNpass;
00840   return fResult;
00841 }
00842 
00843 //......................................................................
00844 
00845 void JobCPath::BeginJob() const
00846 {
00847 //======================================================================
00848 // Purpose: Signal BeginJob for every node in the path
00849 //
00850 //======================================================================
00851 
00852   // First time entering a path, send the begin job message to each
00853   // module in the path
00854   list<JobCModule*>::const_iterator i(fModuleList.begin());
00855   list<JobCModule*>::const_iterator iEnd(fModuleList.end());
00856   for (; i!=iEnd; ++i) if (*i) (*i)->BeginJob();
00857 
00858 }
00859 
00860 //......................................................................
00861 
00862 void JobCPath::SetRefreshMode(bool m) const
00863 {
00864   // This bool is mutable so the const is OK
00865   fIsRefreshRun = m;
00866 }
00867 
00868 //......................................................................
00869 
00870 void JobCPath::PropagateRefreshMode(bool m)
00871 {
00872 //======================================================================
00873 // Tell this path and all others attached that we're in refresh mode m
00874 //======================================================================
00875   JobCPathConnectionHelper h(this);
00876   h.SetRefreshMode(m);
00877 }
00878 
00879 //......................................................................
00880 
00881 void JobCPath::Report() { MSG("JobCReport",Msg::kInfo) << (*this) << "\n"; }
00882 
00883 //......................................................................
00884 
00885 void JobCPath::Run(int n, JobCPath::RunMode_t runmode)
00886 {
00887 //======================================================================
00888 // Purpose: Run records through the path until the path cannot find
00889 //          records to process
00890 //======================================================================
00891   assert(fMom);
00892   JobCRecord rec(fMom);
00893 
00894   this->SetUniquePaths();
00895 
00896 #ifdef SITE_HAS_SIGC
00897   this->SigStartRun(this);
00898 #endif
00899 
00900   // n = 0 is a flag to re-run the current event
00901   if (n == 0) {
00902     this->PropagateRefreshMode(true);
00903     this->EvaluateGraph(&rec);
00904     this->PropagateRefreshMode(false);
00905 #ifdef SITE_HAS_SIGC
00906     this->SigEndRun(this);
00907 #endif
00908     return;
00909   }
00910   else {
00911 
00912     // First time entering a path, send the begin job message to each
00913     // module in the path, as well as the attached paths.
00914     // Use the path helper to process the list of attached paths.
00915     if (this->AtJobStart()) {
00916       JobCPathConnectionHelper h(this);
00917       h.DoBeginJob();
00918     }
00919 
00920     // n != 0 runs new events
00921     bool done  = false;  // Are we done with the run?
00922     int nIn0   = fNin;   // Number events already read at start of run
00923     int nPass0 = fNpass; // Number events already passed at start of run
00924     int nFail0 = fNfail; // Number events already failed at start of run
00925     while (done == false) {
00926       MsgTripWire::Instance().StartRecordSet(); //Record start of record set
00927       rec.Reset();
00928       if (fInput) {
00929         fResult = fInput->Next();
00930         // Reset the prefix on future MsgService calls.
00931         (MsgService::Instance())->SetCurrentRunSnarl(fInput->GetCurrentRun(),
00932                                                      fInput->GetCurrentSnarl());
00933 
00934         MSG("JobC", Msg::kVerbose) << "Result input module is: "
00935                                    << fResult << endl;
00936         this->CheckResult(fResult);
00937 
00938         if (fResult.EndOfInputStream()) {
00939           done |= true;
00940           break;
00941         }
00942       }
00943       this->EvaluateGraph(&rec);
00944 
00945       // Decide if we're done based on number of events processed
00946       // The variables fNin, fNpass, and fNfail get updated as we run
00947       done |= ( (runmode == JobCPath::kRunAll)   && (false) );
00948       done |= ( (runmode == JobCPath::kRunNin)   && (fNin  -nIn0  )==n );
00949       done |= ( (runmode == JobCPath::kRunNpass) && (fNpass-nPass0)==n );
00950       done |= ( (runmode == JobCPath::kRunNfail) && (fNfail-nFail0)==n );
00951 
00952       // Check if we've reached the end of the input stream
00953       if (fResult.EndOfInputStream()) done |= true;
00954 
00955       // Check run limits from the job environmemt
00956       if (JobCEnv::Instance().ContinueRun(fNin) == false) {
00957         done |= true;
00958       }
00959 
00960       // Prevent running forever...
00961       if ( (fNin-nIn0)==JOBCPATH_RUN_LIMIT ) {
00962         MSG("JobC",Msg::kWarning) <<
00963           "Run limit (" << JOBCPATH_RUN_LIMIT << " records) reached.\n";
00964         done |= true;
00965       }
00966     }
00967   }
00968 #ifdef SITE_HAS_SIGC
00969   this->SigEndRun(this);
00970 #endif
00971 }
00972 
00973 //......................................................................
00974 
00975 void JobCPath::RunNin(int n)
00976 {
00977 //======================================================================
00978 // Purpose: Run n records through the path - n=0 is a special case for
00979 //          interactive jobs
00980 //======================================================================
00981   this->Run(n,JobCPath::kRunNin);
00982 }
00983 
00984 //......................................................................
00985 
00986 void JobCPath::RunNpass(int n)
00987 {
00988 //======================================================================
00989 // Purpose: Run records through the path until n pass
00990 //======================================================================
00991   this->Run(n,JobCPath::kRunNpass);
00992 }
00993 
00994 //......................................................................
00995 
00996 void JobCPath::RunNfail(int n)
00997 {
00998 //======================================================================
00999 // Purpose: Run records through the path until n fail
01000 //======================================================================
01001   this->Run(n,JobCPath::kRunNfail);
01002 }
01003 void JobCPath::SetUniquePaths(const char* base)
01004 {
01005     string path = Form("%s/%s",base,fName.c_str());
01006 
01007     list<JobCNode*>::const_iterator nit, done =  fNodeList.end();
01008     for (nit = fNodeList.begin(); nit != done; ++nit) {
01009         JobCModule* mod = (*nit)->GetModule();
01010         string name = Form("%s/%s",path.c_str(),mod->GetName());
01011         mod->SetUniqueName(name.c_str());
01012     }
01013 
01014     JobCGraphVtx* v = 0;
01015     for (int ind = 0; (v=this->GetAttached(ind))!=0; ++ind) {
01016         JobCPath* p2 = dynamic_cast<JobCPath*>(v);
01017         p2->SetUniquePaths(path.c_str());
01018     }
01019 }
01020 

Generated on Mon Nov 23 05:27:02 2009 for loon by  doxygen 1.3.9.1