Gaudi Framework, version v20r3

Generated: 24 Nov 2008

THistSvc.cpp

Go to the documentation of this file.
00001 #include "THistSvc.h"
00002 
00003 #include "GaudiKernel/SvcFactory.h"
00004 #include "GaudiKernel/ISvcLocator.h"
00005 #include "GaudiKernel/MsgStream.h"
00006 #include "GaudiKernel/Tokenizer.h"
00007 #include "GaudiKernel/GaudiException.h"
00008 #include "GaudiKernel/Property.h"
00009 
00010 #include "TROOT.h"
00011 #include "TFile.h"
00012 #include "TDirectory.h"
00013 #include "TKey.h"
00014 #include "TError.h"
00015 #include "TGraph.h"
00016 
00017 #include <sstream>
00018 #include <streambuf>
00019 #include <cstdio>
00020 
00021 using namespace std;
00022 
00023 
00024 DECLARE_SERVICE_FACTORY(THistSvc)
00025 
00026 inline void toupper(std::string &s)
00027 {
00028     std::string::iterator it=s.begin();
00029     while(it != s.end())
00030     {
00031         *it = toupper(*it);
00032         it++;
00033     }
00034 }
00035 
00036 
00037 //*************************************************************************//
00038 
00039 THistSvc::THistSvc( const std::string& name, ISvcLocator* svc )
00040   : Service(name, svc) {
00041 
00042   declareProperty ("Output", m_outputfile );
00043   declareProperty ("Input", m_inputfile );
00044   declareProperty ("AutoSave", m_autoSave=0 );
00045   declareProperty ("PrintAll", m_print=false);
00046 
00047   m_inputfile.declareUpdateHandler ( &THistSvc::setupInputFile,  this );
00048   m_outputfile.declareUpdateHandler( &THistSvc::setupOutputFile, this );
00049 }
00050 
00051 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00052 
00053 THistSvc::~THistSvc() {
00054 
00055 }
00056 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00057 
00058 StatusCode THistSvc::queryInterface( const InterfaceID& riid,
00059                                         void** ppvInterface ) {
00060   StatusCode sc = StatusCode::FAILURE;
00061   if ( ppvInterface ) {
00062     *ppvInterface = 0;
00063 
00064     if ( ITHistSvc::interfaceID().versionMatch(riid) )    {
00065       *ppvInterface = static_cast<ITHistSvc*>(this);
00066       sc = StatusCode::SUCCESS;
00067       addRef();
00068     }
00069     else
00070       sc = Service::queryInterface( riid, ppvInterface );
00071   }
00072   return sc;
00073 }
00074 
00075 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00076 
00077 StatusCode
00078 THistSvc::initialize() {
00079   m_alreadyConnectedOutFiles.clear();
00080   m_alreadyConnectedInFiles.clear();
00081 
00082   StatusCode status = Service::initialize();
00083 
00084   GlobalDirectoryRestore restore;
00085 
00086   if (status.isFailure()) {
00087     MsgStream log ( msgSvc(), name() );
00088     log << MSG::ERROR << "initializing service" << endreq;
00089     return status;
00090   }
00091 
00092   vector<string>::const_iterator itr;
00093   StatusCode st(StatusCode::SUCCESS);
00094 
00095   try {
00096     setupOutputFile( m_outputfile );
00097   } catch ( GaudiException& err ) {
00098     MsgStream msg( msgSvc(), name() );
00099     msg << MSG::ERROR
00100         << "Caught: " << err << endreq;
00101     st = StatusCode::FAILURE;
00102   }
00103 
00104   try {
00105     setupInputFile( m_inputfile );
00106   } catch ( GaudiException& err ) {
00107     MsgStream msg( msgSvc(), name() );
00108     msg << MSG::ERROR
00109         << "Caught: " << err << endreq;
00110     st = StatusCode::FAILURE;
00111   }
00112 
00113   // Protect against multiple instances of TROOT
00114   if ( 0 == gROOT )   {
00115     static TROOT root("root","ROOT I/O");
00116     //    gDebug = 99;
00117   } else {
00118     MsgStream log ( msgSvc(), name() );
00119     log << MSG::VERBOSE << "ROOT already initialized, debug = "
00120         << gDebug<< endreq;
00121   }
00122 
00123 
00124   if (st.isFailure()) {
00125     MsgStream log ( msgSvc(), name() );
00126     log << MSG::FATAL << "Unable to initialize THistSvc" << endreq;
00127   }
00128 
00129   return st;
00130 
00131 }
00132 
00133 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00134 
00135 StatusCode
00136 THistSvc::reinitialize() {
00137 
00138   GlobalDirectoryRestore restore;
00139 
00140   MsgStream log ( msgSvc(), name() );
00141   log << MSG::WARNING << "reinitialize not implemented" << endreq;
00142 
00143 
00144   return StatusCode::SUCCESS;
00145 
00146 }
00147 
00148 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00149 
00150 StatusCode
00151 THistSvc::finalize() {
00152 
00153   GlobalDirectoryRestore restore;
00154 
00155   MsgStream log ( msgSvc(), name() );
00156   log << MSG::DEBUG << "THistSvc::finalize" << endreq;
00157 
00158   uidMap::const_iterator uitr;
00159   for (uitr=m_uids.begin(); uitr != m_uids.end(); ++uitr) {
00160 
00161     TObject* to = uitr->second.obj;
00162 
00163     string dirname("none");
00164     if (to->IsA()->InheritsFrom("TTree")) {
00165       TTree* tr = dynamic_cast<TTree*>(to);
00166       if (tr->GetDirectory() != 0) {
00167         dirname = tr->GetDirectory()->GetPath();
00168       }
00169     } else if (to->IsA()->InheritsFrom("TGraph")) {
00170       if (!uitr->second.temp) {
00171         dirname = uitr->second.file->GetPath();
00172         string id2(uitr->second.id);
00173         id2.erase(0,id2.find("/",1));
00174         id2.erase(id2.rfind("/"), id2.length());
00175         if (id2.find("/") == 0) {
00176           id2.erase(0,1);
00177         }
00178         dirname += id2;
00179       } else {
00180         dirname = "/tmp";
00181       }
00182     } else if (to->IsA()->InheritsFrom("TH1")) {
00183       TH1* th = dynamic_cast<TH1*>(to);
00184       if (th == 0) {
00185         log << MSG::ERROR << "Couldn't dcast: " << uitr->first << endreq;
00186       } else {
00187         if (th->GetDirectory() != 0) {
00188           dirname = th->GetDirectory()->GetPath();
00189         }
00190       }
00191     }
00192 
00193     MsgStream log ( msgSvc(), name() );
00194     log << MSG::DEBUG << "uid: \"" << uitr->first << "\"  temp: "
00195         << uitr->second.temp << "  dir: " << dirname
00196         << endreq;
00197 
00198 
00199 //     if (uitr->second.temp == true) {
00200 //       MsgStream log ( msgSvc(), name() );
00201 //       log << MSG::INFO << "Deleting \"" << uitr->first << "\"" << endreq;
00202 //       delete uitr->second.obj;
00203 //     }
00204   }
00205 
00206   StatusCode sc = write();
00207   if (sc.isFailure()) {
00208     MsgStream log ( msgSvc(), name() );
00209     log << MSG::ERROR << "problems writing histograms" << endreq;
00210   }
00211 
00212   if (m_print) {
00213     log << MSG::INFO << "Listing contents of ROOT files: " << endreq;
00214   }
00215   vector<TFile*> deleted_files;
00216   map<string, pair<TFile*,Mode> >::const_iterator itr;
00217   for (itr = m_files.begin(); itr != m_files.end(); ++itr) {
00218 
00219     if (find(deleted_files.begin(), deleted_files.end(), itr->second.first) ==
00220         deleted_files.end()) {
00221       deleted_files.push_back(itr->second.first);
00222 
00223       log << MSG::DEBUG << "finalizing stream/file " << itr->first << ":"
00224           << itr->second.first->GetName()
00225           << endreq;
00226     } else {
00227       log << MSG::DEBUG << "already finalized stream " << itr->first << endreq;
00228       continue;
00229     }
00230 
00231 
00232     if (m_print && log.level() <= MSG::INFO) {
00233 
00234       log << MSG::INFO;
00235       log << "==> File: " << itr->second.first->GetName()
00236           << "  stream: " << itr->first << endreq;
00237 
00238       itr->second.first->Print("base");
00239     }
00240 
00241     string tmpfn=itr->second.first->GetName();
00242 
00243     itr->second.first->Close();
00244 
00245     if (itr->second.second==SHARE) {
00246       TFile *outputfile;
00247       //Merge File
00248       try {
00249         log << MSG::DEBUG << "Openning Final Output File: " <<m_sharedFiles[itr->first].c_str()<<endreq;
00250         outputfile = new TFile(m_sharedFiles[itr->first].c_str(), "UPDATE");
00251       } catch (const std::exception& Exception) {
00252       log << MSG::ERROR << "exception caught while trying to open root"
00253           << " file for appending: " << Exception.what() << std::endl
00254           << "  -> file probably corrupt." << endreq;
00255       return StatusCode::FAILURE;
00256       } catch (...) {
00257         log << MSG::ERROR << "Problems opening output file  \"" << m_sharedFiles[itr->first]
00258             << "\" for append: probably corrupt" << endreq;
00259         return StatusCode::FAILURE;
00260       }
00261 
00262       log << MSG::DEBUG << "THistSvc::write()::Merging Rootfile "<<endreq;
00263       TFile *inputfile;
00264       try {
00265         log << MSG::DEBUG << "Openning again Temporary File: " <<tmpfn.c_str()<<endreq;
00266         inputfile=new TFile(tmpfn.c_str(),"READ");
00267       } catch (const std::exception& Exception) {
00268         log << MSG::ERROR << "exception caught while trying to open root"
00269             << " file for appending: " << Exception.what() << std::endl
00270             << "  -> file probably corrupt." << endreq;
00271         return StatusCode::FAILURE;
00272       } catch (...) {
00273         log << MSG::ERROR << "Problems opening output file  \"" << tmpfn.c_str()
00274             << "\" for append: probably corrupt" << endreq;
00275         return StatusCode::FAILURE;
00276       }
00277 
00278       MergeRootFile(outputfile, inputfile);
00279 
00280       outputfile->Write();
00281       outputfile->Close();
00282       inputfile->Close();
00283 
00284       log << MSG::DEBUG << "Trying to remove temporary file \"" << tmpfn
00285           << "\""<<endreq;
00286 
00287       std::remove(tmpfn.c_str());
00288     }
00289     delete itr->second.first;
00290   }
00291 
00292   m_sharedFiles.clear();
00293   m_fileStreams.clear();
00294   m_files.clear();
00295   m_uids.clear();
00296   m_ids.clear();
00297   m_tobjs.clear();
00298 
00299   return Service::finalize();
00300 }
00301 
00302 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00303 
00304 bool
00305 THistSvc::browseTDir(TDirectory *dir) const {
00306 
00307   if (dir == 0) {
00308     std::cerr << "TDirectory == 0" << std::endl;
00309     return false;
00310   }
00311 
00312   GlobalDirectoryRestore restore;
00313 
00314   MsgStream log(msgSvc(), name());
00315 
00316   dir->cd();
00317 
00318 
00319   cout << "-> " << dir->GetPath() << "  "
00320        << dir->GetListOfKeys()->GetSize() << endl;
00321 
00322   //  TIter nextkey(dir->GetListOfKeys());
00323   TIter nextkey(dir->GetList());
00324   while (TKey *key = (TKey*)nextkey()) {
00325 
00326     TObject *obj = key->ReadObj();
00327     if (obj == 0) { cout << key->GetName() << " obj==0"<< endl; continue; }
00328     //    if (obj->IsA()->InheritsFrom("TDirectory")) {
00329       cout << "  Key: " << key->GetName() << "   "
00330            << " tit: " << obj->GetTitle() << "   "
00331            << " (" << key->GetClassName() << ")" << endl;
00332       //    }
00333   }
00334 
00335   nextkey = dir->GetListOfKeys();
00336   while (TKey *key = (TKey*)nextkey()) {
00337 
00338     TObject *obj = key->ReadObj();
00339     if (obj == 0) { cout << key->GetName() << " obj==0"<< endl; continue; }
00340     if (obj->IsA()->InheritsFrom("TDirectory")) {
00341       TDirectory *tt = dynamic_cast<TDirectory*>(obj);
00342       browseTDir(tt);
00343     }
00344   }
00345 
00346   return true;
00347 }
00348 
00349 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00350 
00351 StatusCode
00352 THistSvc::getTHists(TDirectory *td, TList & tl) const {
00353 
00354   MsgStream log ( msgSvc(), name() );
00355   GlobalDirectoryRestore restore;
00356 
00357   gErrorIgnoreLevel = kBreak;
00358 
00359   if (!td->cd()) {
00360     log << MSG::ERROR << "No such TDirectory \"" << td->GetPath() << "\""
00361         << endreq;
00362     return StatusCode::FAILURE;
00363   }
00364 
00365   TIter nextkey(td->GetList());
00366   while (TObject *key = (TObject*)nextkey()) {
00367     if (key != 0) {
00368       if (key->IsA()->InheritsFrom("TH1")) { tl.Add(key); }
00369     }
00370   }
00371 
00372 
00373   return StatusCode::SUCCESS;
00374 
00375 }
00376 
00377 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00378 
00379 StatusCode
00380 THistSvc::getTHists(const std::string& dir, TList & tl) const {
00381 
00382   MsgStream log ( msgSvc(), name() );
00383   GlobalDirectoryRestore restore;
00384 
00385   gErrorIgnoreLevel = kBreak;
00386 
00387   StatusCode sc;
00388 
00389   if (!gDirectory->cd(dir.c_str())) {
00390     log << MSG::ERROR << "No such TDirectory \"" << dir << "\""
00391          << endreq;
00392     sc = StatusCode::FAILURE;
00393   } else {
00394     sc = getTHists(gDirectory,tl);
00395   }
00396 
00397   return sc;
00398 
00399 }
00400 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00401 
00402 StatusCode
00403 THistSvc::getTTrees(TDirectory *td, TList & tl) const {
00404 
00405   MsgStream log ( msgSvc(), name() );
00406   GlobalDirectoryRestore restore;
00407 
00408   gErrorIgnoreLevel = kBreak;
00409 
00410   if (!td->cd()) {
00411     log << MSG::ERROR << "No such TDirectory \"" << td->GetPath() << "\""
00412         << endreq;
00413     return StatusCode::FAILURE;
00414   }
00415 
00416   TIter nextkey(td->GetList());
00417   while (TObject *key = (TObject*)nextkey()) {
00418     if (key != 0) {
00419       if (key->IsA()->InheritsFrom("TTree")) { tl.Add(key); }
00420     }
00421   }
00422 
00423   return StatusCode::SUCCESS;
00424 
00425 }
00426 
00427 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00428 
00429 StatusCode
00430 THistSvc::getTTrees(const std::string& dir, TList & tl) const {
00431 
00432   MsgStream log ( msgSvc(), name() );
00433   GlobalDirectoryRestore restore;
00434 
00435   gErrorIgnoreLevel = kBreak;
00436 
00437   StatusCode sc;
00438 
00439   if (!gDirectory->cd(dir.c_str())) {
00440     log << MSG::ERROR << "No such TDirectory \"" << dir << "\""
00441          << endreq;
00442     sc = StatusCode::FAILURE;
00443   } else {
00444     sc = getTTrees(gDirectory,tl);
00445   }
00446 
00447   return sc;
00448 
00449 }
00450 
00451 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00452 
00453 StatusCode
00454 THistSvc::deReg(TObject* obj) {
00455 
00456   objMap::iterator itr = m_tobjs.find(obj);
00457   if (itr != m_tobjs.end()) {
00458     THistID hid = itr->second;
00459 
00460     uidMap::iterator itr2 = m_uids.find(hid.id);
00461     if (itr2 == m_uids.end()) {
00462       MsgStream log ( msgSvc(), name() );
00463       log << MSG::ERROR << "Problems deregistering TObject \""
00464           << obj->GetName()
00465           << "\" with id \"" << hid.id << "\"" << endreq;
00466       return StatusCode::FAILURE;
00467     }
00468 
00469     std::string id,root,rem;
00470     parseString(hid.id, root, rem);
00471 
00472     idMap::iterator itr3;
00473     bool found(false);
00474 
00475     std::pair<idMap::iterator, idMap::iterator> mitr = m_ids.equal_range(rem);
00476     if (mitr.first == mitr.second) {
00477       MsgStream log ( msgSvc(), name() );
00478       log << MSG::ERROR << "Problems deregistering TObject \""
00479           << obj->GetName()
00480           << "\" with id \"" << hid.id << "\"" << endreq;
00481       return StatusCode::FAILURE;
00482     } else {
00483       for (itr3 = mitr.first; itr3 != mitr.second; ++itr3) {
00484         if (itr3->second.obj == obj) {
00485           found = true;
00486           break;
00487         }
00488       }
00489       if (!found) {
00490         MsgStream log ( msgSvc(), name() );
00491         log << MSG::ERROR << "Problems deregistering TObject \""
00492             << obj->GetName()
00493             << "\" with id \"" << hid.id << "\"" << endreq;
00494       }
00495     }
00496 
00497     m_tobjs.erase(itr);
00498     m_uids.erase(itr2);
00499     m_ids.erase(itr3);
00500 
00501     return StatusCode::SUCCESS;
00502 
00503   } else {
00504     MsgStream log ( msgSvc(), name() );
00505     log << MSG::ERROR << "Cannot unregister TObject \"" << obj->GetName()
00506         << "\": not known to THistSvc" << endreq;
00507     return StatusCode::FAILURE;
00508   }
00509 
00510 }
00511 
00512 
00513 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00514 
00515 StatusCode
00516 THistSvc::deReg(const std::string& id) {
00517 
00518   uidMap::iterator itr = m_uids.find(id);
00519   if (itr == m_uids.end()) {
00520     MsgStream log ( msgSvc(), name() );
00521     log << MSG::ERROR << "Problems deregistering id \""
00522         << id << "\"" << endreq;
00523     return StatusCode::FAILURE;
00524   }
00525 
00526   TObject* obj = itr->second.obj;
00527 
00528   return deReg(obj);
00529 }
00530 
00531 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00532 
00533 StatusCode
00534 THistSvc::regHist(const std::string& id) {
00535 
00536   TH1 *hist(0);
00537 
00538   return regHist_i(hist, id);
00539 }
00540 
00541 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00542 
00543 StatusCode
00544 THistSvc::regHist(const std::string& id, TH1* hist) {
00545   return regHist_i(hist, id);
00546 }
00547 
00548 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00549 
00550 StatusCode
00551 THistSvc::regHist(const std::string& id, TH2* hist) {
00552   return regHist_i(hist, id);
00553 }
00554 
00555 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00556 
00557 StatusCode
00558 THistSvc::regHist(const std::string& id, TH3* hist) {
00559   return regHist_i(hist, id);
00560 }
00561 
00562 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00563 
00564 StatusCode
00565 THistSvc::regTree(const std::string& id) {
00566   TTree *hist(0);
00567   return regHist_i(hist, id);
00568 }
00569 
00570 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00571 
00572 StatusCode
00573 THistSvc::regTree(const std::string& id, TTree* hist) {
00574   StatusCode sc = regHist_i(hist, id);
00575   if (hist != 0 && m_autoSave != 0 && sc.isSuccess()) {
00576     hist->SetAutoSave(m_autoSave);
00577   }
00578   return sc;
00579 }
00580 
00581 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00582 
00583 StatusCode
00584 THistSvc::regGraph(const std::string& id) {
00585   TGraph *hist(0);
00586   return regHist_i(hist, id);
00587 }
00588 
00589 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00590 
00591 StatusCode
00592 THistSvc::regGraph(const std::string& id, TGraph* hist) {
00593   if ( strcmp(hist->GetName(),"Graph") == 0 ) {
00594 
00595     std::string id2(id);
00596     string::size_type i = id2.rfind("/");
00597     if (i != string::npos) {
00598       id2.erase(0,i+1);
00599     }
00600 
00601     MsgStream log ( msgSvc(), name() );
00602     log << MSG::INFO << "setting name of TGraph id: \"" << id << "\" to \""
00603         << id2 << "\" since it is unset" << endreq;
00604     hist->SetName(id2.c_str());
00605   }
00606 
00607   return regHist_i(hist, id);
00608 }
00609 
00610 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00611 
00612 StatusCode
00613 THistSvc::getHist(const std::string& id, TH1*& hist) const {
00614   return getHist_i(id, hist);
00615 }
00616 
00617 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00618 
00619 StatusCode
00620 THistSvc::getHist(const std::string& id, TH2*& hist) const {
00621   return getHist_i(id, hist);
00622 }
00623 
00624 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00625 
00626 StatusCode
00627 THistSvc::getHist(const std::string& id, TH3*& hist) const {
00628   return getHist_i(id, hist);
00629 }
00630 
00631 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00632 
00633 std::vector<std::string>
00634 THistSvc::getHists() const {
00635 
00636   std::vector<std::string> names;
00637   names.reserve(m_uids.size());
00638 
00639   uidMap::const_iterator itr;
00640   for (itr = m_uids.begin(); itr != m_uids.end(); ++itr) {
00641     THistID tid = itr->second;
00642 
00643     if (tid.obj->IsA()->InheritsFrom("TH1")) {
00644       names.push_back(itr->first);
00645     }
00646 
00647   }
00648 
00649   return names;
00650 
00651 }
00652 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00653 
00654 StatusCode
00655 THistSvc::getTree(const std::string& id, TTree*& hist) const {
00656   return getHist_i(id, hist);
00657 }
00658 
00659 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00660 
00661 std::vector<std::string>
00662 THistSvc::getTrees() const {
00663 
00664   std::vector<std::string> names;
00665   names.reserve(m_uids.size());
00666 
00667   uidMap::const_iterator itr;
00668   for (itr = m_uids.begin(); itr != m_uids.end(); ++itr) {
00669     THistID tid = itr->second;
00670 
00671     if (tid.obj->IsA()->InheritsFrom("TTree")) {
00672       names.push_back(itr->first);
00673     }
00674 
00675   }
00676 
00677   return names;
00678 
00679 }
00680 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00681 
00682 StatusCode
00683 THistSvc::getGraph(const std::string& id, TGraph*& hist) const {
00684   return getHist_i(id, hist);
00685 }
00686 
00687 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00688 
00689 std::vector<std::string>
00690 THistSvc::getGraphs() const {
00691 
00692   std::vector<std::string> names;
00693   names.reserve(m_uids.size());
00694 
00695   uidMap::const_iterator itr;
00696   for (itr = m_uids.begin(); itr != m_uids.end(); ++itr) {
00697     THistID tid = itr->second;
00698 
00699     if (tid.obj->IsA()->InheritsFrom("TGraph")) {
00700       names.push_back(itr->first);
00701     }
00702 
00703   }
00704 
00705   return names;
00706 
00707 }
00708 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00709 
00710 StatusCode
00711 THistSvc::readHist(const std::string& id, TH1*& hist) const {
00712   return readHist_i(id, hist);
00713 }
00714 
00715 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00716 
00717 StatusCode
00718 THistSvc::readHist(const std::string& id, TH2*& hist) const {
00719   return readHist_i(id, hist);
00720 }
00721 
00722 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00723 
00724 StatusCode
00725 THistSvc::readHist(const std::string& id, TH3*& hist) const {
00726   return readHist_i(id, hist);
00727 }
00728 
00729 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00730 
00731 StatusCode
00732 THistSvc::readTree(const std::string& id, TTree*& hist) const {
00733   return readHist_i(id, hist);
00734 }
00735 
00736 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00737 
00738 bool
00739 THistSvc::findStream(const string& id, string& stream, string& rem,
00740                    TFile*& file) const {
00741 
00742   string::size_type pos = id.find("/");
00743 
00744   if (pos == string::npos) {
00745     stream = "temp";
00746     rem = id;
00747   } else if (pos != 0) {
00748     stream = "temp";
00749     rem = id;
00750   } else {
00751 
00752     string::size_type pos2 = id.find("/",pos+1);
00753 
00754     if (pos2 == string::npos) {
00755       MsgStream log( msgSvc(), name() );
00756       log << MSG::ERROR << "badly formed Hist/Tree id: \"" << id << "\""
00757           << endreq;
00758       return false;
00759     }
00760 
00761     parseString(id,stream,rem);
00762 
00763   }
00764 
00765   if (stream == "temp") {
00766     file = 0;
00767     return true;
00768   }
00769 
00770   map< string,pair<TFile*,Mode> >::const_iterator itr = m_files.find(stream);
00771   if (itr != m_files.end()) {
00772     file = itr->second.first;
00773   } else {
00774     file = 0;
00775     MsgStream log( msgSvc(), name() );
00776     log << MSG::WARNING << "no stream \"" << stream
00777         << "\" associated with id: \"" << id << "\""
00778         << endreq;
00779   }
00780 
00781   return true;
00782 
00783 }
00784 
00785 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00786 
00787 void
00788 THistSvc::parseString(const string& id, string& root, string& rem) const {
00789   string::size_type pos = id.find("/");
00790 
00791   if (pos == string::npos) {
00792     root = "";
00793     rem = id;
00794     return;
00795   }
00796 
00797   if (pos == 0) {
00798     parseString(id.substr(1,id.length()),root,rem);
00799   } else {
00800     root = id.substr(0,pos);
00801     rem = id.substr(pos+1,id.length());
00802   }
00803 
00804 }
00805 
00806 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00807 
00808 void
00809 THistSvc::setupInputFile( Property& /*m_inputfile*/ )
00810 {
00811   StatusCode sc = StatusCode::SUCCESS;
00812 
00813   typedef std::vector<std::string> Strings_t;
00814   for ( Strings_t::const_iterator
00815           itr  = m_inputfile.value().begin(),
00816           iEnd = m_inputfile.value().end();
00817         itr != iEnd;
00818         ++itr ) {
00819     if ( m_alreadyConnectedInFiles.end() ==
00820          m_alreadyConnectedInFiles.find( *itr ) ) {
00821       if ( connect(*itr).isFailure() ) {
00822         sc = StatusCode::FAILURE;
00823       } else {
00824         m_alreadyConnectedInFiles.insert( *itr );
00825       }
00826     }
00827   }
00828 
00829   if ( !sc.isSuccess() ) {
00830     throw GaudiException( "Problem connecting inputfile !!", name(),
00831                           StatusCode::FAILURE );
00832   }
00833   return;
00834 }
00835 
00836 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00837 
00838 void
00839 THistSvc::setupOutputFile( Property& /*m_outputfile*/ )
00840 {
00841   StatusCode sc = StatusCode::SUCCESS;
00842 
00843   typedef std::vector<std::string> Strings_t;
00844   for ( Strings_t::const_iterator
00845           itr  = m_outputfile.value().begin(),
00846           iEnd = m_outputfile.value().end();
00847         itr != iEnd;
00848         ++itr ) {
00849     if ( m_alreadyConnectedOutFiles.end() ==
00850          m_alreadyConnectedOutFiles.find( *itr ) ) {
00851       if ( connect(*itr).isFailure() ) {
00852         sc = StatusCode::FAILURE;
00853       } else {
00854         m_alreadyConnectedOutFiles.insert( *itr );
00855       }
00856     }
00857   }
00858 
00859   if ( !sc.isSuccess() ) {
00860     throw GaudiException( "Problem connecting outputfile !!", name(),
00861                           StatusCode::FAILURE );
00862   }
00863   return;
00864 }
00865 
00866 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00867 
00868 void
00869 THistSvc::updateFiles() {
00870 
00871   // If TTrees grow beyond TTree::fgMaxFileSize, a new file is
00872   // automatically created by root, and the old one closed. We
00873   // need to migrate all the UIDs over to show the correct file
00874   // pointer. This is ugly.
00875 
00876   uidMap::iterator uitr, uitr2;
00877   for (uitr=m_uids.begin(); uitr != m_uids.end(); ++uitr) {
00878     TObject* to = uitr->second.obj;
00879     TFile* oldFile = uitr->second.file;
00880     if (to->IsA()->InheritsFrom("TTree")) {
00881       TTree* tr = dynamic_cast<TTree*>(to);
00882       TFile* newFile = tr->GetCurrentFile();
00883 
00884       if (oldFile != newFile) {
00885         std::string newFileName = newFile->GetName();
00886         std::string oldFileName(""), streamName, rem;
00887         TFile* dummy;
00888         findStream(uitr->second.id, streamName, rem, dummy);
00889 
00890         MsgStream log( msgSvc(), name() );
00891         log << MSG::DEBUG << "migrating uid: " << uitr->second.id
00892             << "   stream: " << streamName << "   newFile: " << newFileName
00893             << endreq;
00894 
00895         map<string, pair<TFile*,Mode> >::iterator itr;
00896         for (itr=m_files.begin(); itr!= m_files.end(); ++itr) {
00897           if (itr->second.first == oldFile) {
00898             itr->second.first = newFile;
00899 
00900           }
00901         }
00902 
00903         uitr2 = uitr;
00904         for (uitr2++; uitr2 != m_uids.end(); ++uitr2) {
00905           if (uitr2->second.file == oldFile) {
00906             uitr2->second.file = newFile;
00907           }
00908         }
00909 
00910         streamMap::iterator sitr;
00911         for (sitr = m_fileStreams.begin(); sitr!=m_fileStreams.end(); ++sitr) {
00912           if (sitr->second == streamName) {
00913             oldFileName = sitr->first;
00914             break;
00915           }
00916         }
00917 
00918         if (oldFileName != "") {
00919           while ( (sitr=m_fileStreams.find(oldFileName)) != m_fileStreams.end() ) {
00920             log << MSG::DEBUG << "changing filename \"" << oldFileName
00921                 << "\" to \"" << newFileName << "\" for stream \""
00922                 << sitr->second << "\"" << endreq;
00923             m_fileStreams.erase(sitr);
00924             m_fileStreams.insert( make_pair<std::string,std::string>(newFileName,streamName) );
00925           }
00926 
00927 
00928         } else {
00929           log << MSG::ERROR
00930               << "Problems updating fileStreams with new file name" << endreq;
00931         }
00932 
00933       }
00934 
00935     }
00936   }
00937 
00938 }
00939 
00940 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00941 
00942 StatusCode
00943 THistSvc::write() {
00944 
00945   updateFiles();
00946 
00947   MsgStream log(msgSvc(), name() );
00948 
00949   map<string, pair<TFile*,Mode> >::const_iterator itr;
00950   for (itr=m_files.begin(); itr!= m_files.end(); ++itr) {
00951     if (itr->second.second == WRITE || itr->second.second == UPDATE
00952         ||itr->second.second==SHARE) {
00953       itr->second.first->Write("",TObject::kOverwrite);
00954     } else if (itr->second.second == APPEND) {
00955       itr->second.first->Write("");
00956     }
00957   }
00958 
00959 
00960   log << MSG::DEBUG << "THistSvc::write()::List of Files connected in ROOT "
00961       <<endreq;
00962 
00963   TSeqCollection *filelist=gROOT->GetListOfFiles();
00964   for (int ii=0; ii<filelist->GetEntries(); ii++) {
00965     log << MSG::DEBUG
00966         << "THistSvc::write()::List of Files connected in ROOT: \""
00967         <<filelist->At(ii)->GetName()<<"\""<<endreq;
00968   }
00969 
00970   return StatusCode::SUCCESS;
00971 
00972 }
00973 
00974 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
00975 
00976 StatusCode
00977 THistSvc::connect(const std::string& ident) {
00978 
00979   MsgStream log ( msgSvc(), name() );
00980   Tokenizer tok(true);
00981 
00982   string::size_type loc = ident.find(" ");
00983   string stream = ident.substr(0,loc);
00984   char typ(0);
00985   typedef std::pair<std::string,std::string>      Prop;
00986   std::vector<Prop> props;
00987   string val,VAL,TAG,filename,db_typ("ROOT");
00988 
00989   tok.analyse(ident.substr(loc+1,ident.length()), " ", "", "", "=", "'", "'");
00990 
00991   for ( Tokenizer::Items::iterator i = tok.items().begin(); i != tok.items().end(); i++)    {
00992     const std::string& tag = (*i).tag();
00993     TAG = tag;
00994     toupper(TAG);
00995 
00996     val = (*i).value();
00997     VAL = val;
00998     toupper(VAL);
00999 
01000     if (TAG == "FILE" || TAG == "DATAFILE") {
01001       filename = val;
01002       removeDoubleSlash( filename );
01003     } else if ( TAG == "OPT" ) {
01004       if ( VAL == "APPEND" || VAL == "UPDATE" ) {
01005         typ = 'A';
01006       } else if ( VAL == "CREATE" || VAL == "NEW" || VAL == "WRITE" ) {
01007         typ = 'N';
01008       } else if ( VAL == "RECREATE" ) {
01009         typ = 'R';
01010       } else if (VAL == "SHARE") {
01011         typ = 'S';
01012       } else if ( VAL == "OLD" || VAL == "READ" ) {
01013         typ = 'O';
01014       } else {
01015         log << MSG::ERROR << "Unknown OPT: \"" << (*i).value() << "\""
01016             << endreq;
01017         typ = 0;
01018       }
01019     } else if (TAG == "TYP") {
01020       db_typ = (*i).value();
01021     } else {
01022       props.push_back( Prop((*i).tag(), (*i).value()));
01023     }
01024 
01025   }
01026 
01027   if (stream == "temp") {
01028     log << MSG::ERROR << "in JobOption \"" << ident
01029         << "\": stream name \"temp\" reserved."
01030         << endreq;
01031     return StatusCode::FAILURE;
01032   }
01033 
01034   if (db_typ != "ROOT") {
01035     log << MSG::ERROR << "in JobOption \"" << ident
01036         << "\": technology type \"" << db_typ << "\" not supported."
01037         << endreq;
01038     return StatusCode::FAILURE;
01039   }
01040 
01041 
01042   if (m_files.find(stream) != m_files.end()) {
01043     log << MSG::ERROR << "in JobOption \"" << ident
01044         << "\":\n stream \"" << stream << "\" already connected to file: \""
01045         << m_files[stream].first->GetName() << "\""
01046         << endreq;
01047     return StatusCode::FAILURE;
01048   }
01049 
01050   Mode newMode;
01051   if (typ == 'O') {
01052     newMode = THistSvc::READ;
01053   } else if (typ == 'N') {
01054     newMode = THistSvc::WRITE;
01055   } else if (typ == 'A') {
01056     newMode = THistSvc::APPEND;
01057   } else if (typ == 'R') {
01058     newMode = THistSvc::UPDATE;
01059   } else if (typ == 'S') {
01060     newMode = THistSvc::SHARE;
01061   } else {
01062     // something else?
01063     log << MSG::ERROR << "No OPT= specified or unknown access mode in: "
01064         << ident << endreq;
01065     return StatusCode::FAILURE;
01066   }
01067 
01068   // Is this file already connected to another stream?
01069   if (m_fileStreams.find(filename) != m_fileStreams.end()) {
01070     std::pair<streamMap::iterator, streamMap::iterator> fitr =
01071       m_fileStreams.equal_range(filename);
01072 
01073     std::string oldstream = (fitr.first)->second;
01074 
01075     std::pair<TFile*,Mode> f_info = m_files[oldstream];
01076 
01077     if (newMode != f_info.second) {
01078       log << MSG::ERROR << "in JobOption \"" << ident
01079           << "\":\n file \"" << filename << "\" already opened by stream: \""
01080           << oldstream << "\" with different access mode."
01081           << endreq;
01082       return StatusCode::FAILURE;
01083     } else {
01084       TFile *f2 = f_info.first;
01085       m_files[stream] = make_pair<TFile*,Mode>(f2,newMode);
01086       log << MSG::DEBUG << "Connecting stream: \"" << stream
01087           << "\" to previously opened TFile: \"" << filename << "\""
01088           << endreq;
01089       return StatusCode::SUCCESS;
01090     }
01091   }
01092 
01093 
01094   TFile *f(0) ;
01095   if (newMode == THistSvc::READ) {
01096     // old file
01097 
01098     try {
01099       f = TFile::Open(filename.c_str(),"READ");
01100     } catch (const std::exception& Exception) {
01101       log << MSG::ERROR << "exception caught while trying to open root"
01102           << " file for reading: " << Exception.what() << std::endl
01103           << "  -> file probably corrupt." << endreq;
01104       return StatusCode::FAILURE;
01105     } catch (...) {
01106       log << MSG::ERROR << "Problems opening input file  \"" << filename
01107           << "\": probably corrupt" << endreq;
01108       return StatusCode::FAILURE;
01109     }
01110 
01111     if (!f->IsOpen()) {
01112       log << MSG::ERROR << "Unable to open input file \"" << filename
01113           << "\": file does not exist" << endreq;
01114       return StatusCode::FAILURE;
01115     }
01116 
01117 
01118   } else if (newMode == THistSvc::WRITE) {
01119     // new file
01120 
01121     f = TFile::Open(filename.c_str(),"NEW");
01122     if (!f->IsOpen()) {
01123       log << MSG::ERROR << "Unable to create new output file \"" << filename
01124           << "\" for writing: file already exists" << endreq;
01125       return StatusCode::FAILURE;
01126     }
01127 
01128   } else if (newMode == THistSvc::APPEND) {
01129     // update file
01130 
01131     try {
01132       f =  TFile::Open(filename.c_str(),"UPDATE");
01133     } catch (const std::exception& Exception) {
01134       log << MSG::ERROR << "exception caught while trying to open root"
01135           << " file for appending: " << Exception.what() << std::endl
01136           << "  -> file probably corrupt." << endreq;
01137       return StatusCode::FAILURE;
01138     } catch (...) {
01139       log << MSG::ERROR << "Problems opening output file  \"" << filename
01140           << "\" for append: probably corrupt" << endreq;
01141       return StatusCode::FAILURE;
01142     }
01143 
01144     if (!f->IsOpen()) {
01145       log << MSG::ERROR << "Unable to open output file \"" << filename
01146           << "\" for appending" << endreq;
01147       return StatusCode::FAILURE;
01148     }
01149 
01150   } else if (newMode == THistSvc::SHARE) {
01151     // SHARE file type
01152     //For SHARE files, all data will be stored in a temp file and will be merged into the target file
01153     //in write() when finalize(), this help to solve some confliction. e.g. with storegate
01154 
01155   static int ishared = 0;
01156   stringstream out;
01157   string realfilename=filename;
01158   out << ishared;
01159   filename = string("tmp_THistSvc_")+out.str()+string(".root");
01160 
01161   log << MSG::DEBUG << "Creating temp file \"" << filename
01162       << "\" and realfilename="<<realfilename << endreq;
01163   m_sharedFiles[stream]=realfilename;
01164 
01165   try {
01166   f = TFile::Open(filename.c_str(),"NEW");
01167   } catch (const std::exception& Exception) {
01168     log << MSG::ERROR << "exception caught while trying to open root"
01169         << " file for appending: " << Exception.what() << std::endl
01170         << "  -> file probably corrupt." << endreq;
01171   return StatusCode::FAILURE;
01172   } catch (...) {
01173     log << MSG::ERROR << "Problems opening output file  \"" << filename
01174         << "\" for append: probably corrupt" << endreq;
01175   return StatusCode::FAILURE;
01176   }
01177 
01178   if (!f->IsOpen()) {
01179     log << MSG::ERROR << "Unable to open output file \"" << filename
01180         << "\" for appending" << endreq;
01181   return StatusCode::FAILURE;
01182   }
01183 
01184 } else if (newMode == THistSvc::UPDATE) {
01185     // update file
01186 
01187     try {
01188       f =  TFile::Open(filename.c_str(),"RECREATE");
01189     } catch (const std::exception& Exception) {
01190       log << MSG::ERROR << "exception caught while trying to open root"
01191           << " file for updating: " << Exception.what() << std::endl
01192           << "  -> file probably corrupt." << endreq;
01193       return StatusCode::FAILURE;
01194     } catch (...) {
01195       log << MSG::ERROR << "Problems opening output file  \"" << filename
01196           << "\" for update: probably corrupt" << endreq;
01197       return StatusCode::FAILURE;
01198     }
01199 
01200     if (!f->IsOpen()) {
01201       log << MSG::ERROR << "Unable to open output file \"" << filename
01202           << "\" for updating" << endreq;
01203       return StatusCode::FAILURE;
01204     }
01205 
01206   }
01207 
01208   m_files[stream] = make_pair<TFile*,Mode>(f,newMode);
01209   m_fileStreams.insert(make_pair<std::string,std::string>(filename,stream));
01210 
01211   log << MSG::DEBUG << "Opening TFile \"" << filename << "\"  stream: \""
01212       << stream << "\"  mode: \"" << typ << "\""
01213       << endreq;
01214 
01215   return StatusCode::SUCCESS;
01216 }
01217 
01218 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
01219 
01220 TDirectory*
01221 THistSvc::changeDir(const THistSvc::THistID& hid) const {
01222 
01223   string uid = hid.id;
01224   TFile* file = hid.file;
01225   string stream, fdir, bdir, dir, id;
01226 
01227   if (file != 0) {
01228     file->cd("/");
01229   } else {
01230     gROOT->cd();
01231   }
01232 
01233   fdir = uid;
01234   bdir = dirname(fdir);
01235 
01236   while ( (dir = dirname(fdir)) != "") {
01237     if (! gDirectory->GetKey(dir.c_str())) {
01238       gDirectory->mkdir(dir.c_str());
01239     }
01240     gDirectory->cd(dir.c_str());
01241   }
01242 
01243   return gDirectory;
01244 
01245 }
01246 
01247 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
01248 
01249 std::string
01250 THistSvc::dirname(std::string& dir) const {
01251 
01252 
01253   string::size_type i = dir.find("/");
01254 
01255   if (i == string::npos) {
01256     return "";
01257   }
01258 
01259   if ( i == 0 ) {
01260     dir.erase(0,1);
01261     return dirname(dir);
01262   }
01263 
01264   string root = dir.substr(0,i);
01265   dir.erase(0,i);
01266 
01267   return root;
01268 
01269 }
01270 
01271 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
01272 
01273 THistSvc::GlobalDirectoryRestore::GlobalDirectoryRestore() {
01274   m_gd = gDirectory;
01275   m_gf = gFile;
01276   m_ge = gErrorIgnoreLevel;
01277 }
01278 
01279 THistSvc::GlobalDirectoryRestore::~GlobalDirectoryRestore() {
01280   gDirectory = m_gd;
01281   gFile = m_gf;
01282   gErrorIgnoreLevel = m_ge;
01283 }
01284 
01285 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
01286 
01287 void
01288 THistSvc::removeDoubleSlash(std::string& id) const {
01289 
01290   while (id.find("//") != std::string::npos) {
01291     id.replace(id.find("//"),2,"/");
01292   }
01293 
01294 }
01295 
01296 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//
01297 
01298 void THistSvc::MergeRootFile(TDirectory *target, TDirectory *source) {
01299 
01300   MsgStream log(msgSvc(), name() );
01301 
01302   log <<MSG::DEBUG << "Target path: " << target->GetPath() << endreq;
01303   TString path( (char*)strstr(target->GetPath(), ":") );
01304   path.Remove( 0, 2);
01305 
01306   source->cd(path);
01307   TDirectory *current_sourcedir = gDirectory;
01308 
01309   // loop over all keys in this directory
01310   TList *lkeys=current_sourcedir->GetListOfKeys();
01311   int nkeys=lkeys->GetEntries();
01312   TKey *key;
01313   for (int jj=0; jj<nkeys; jj++) {
01314     key=(TKey*) lkeys->At(jj);
01315     string pathnameinsource=current_sourcedir->GetPath()+string("/")+key->GetName();
01316     log <<MSG::DEBUG << "Reading Key:" << pathnameinsource << endreq;
01317     //key->Dump();
01318     //TObject *obj=key->ReadObj();
01319     TObject *obj=source->Get(pathnameinsource.c_str());
01320 
01321     if (obj->IsA()->InheritsFrom("TDirectory") ) {
01322       // it's a subdirectory
01323 
01324       log <<MSG::DEBUG << "Found subdirectory " << obj->GetName()
01325           << endreq;
01326 
01327       // create a new subdir of same name and title in the target file
01328       target->cd();
01329       TDirectory *newtargetdir =
01330         target->mkdir(obj->GetName(), obj->GetTitle() );
01331 
01332       MergeRootFile(newtargetdir, source);
01333 
01334     } else if (obj->IsA()->InheritsFrom("TTree")) {
01335       log <<MSG::DEBUG << "Found TTree " << obj->GetName() << endreq;
01336       TTree *mytree=dynamic_cast<TTree*>(obj);
01337       int nentries=(int) mytree->GetEntries();
01338       mytree->SetBranchStatus("*",1);
01339 
01340       log <<MSG::DEBUG << "Dumping TTree " << nentries <<" entries"
01341           << endreq;
01342       //mytree->Print();
01343       //for (int ij=0; ij<nentries; ij++) {
01344       //log <<MSG::DEBUG << "Dumping TTree Show( " << ij <<" )"
01345       //<< endreq;
01346       //mytree->Show(ij);
01347       //}
01348       target->cd();
01349       mytree->CloneTree();
01350 
01351       //log <<MSG::DEBUG << "Writing TTree to target file: ( "
01352       //<< mycopiedtree->Write(key->GetName()) <<" ) bytes written"
01353       //<< endreq;
01354 
01355     } else if (obj) {
01356       target->cd();
01357       obj->Write(key->GetName() );
01358     }
01359 
01360   } // while ( ( TKey *key = (TKey*)nextkey() ) )
01361 
01362   // save modifications to target file
01363 
01364 }
01365 
01366 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *//

Generated at Mon Nov 24 14:38:49 2008 for Gaudi Framework, version v20r3 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004