CMS 3D CMS Logo

TrivialFileCatalog.cc

Go to the documentation of this file.
00001 /* 
00002    Concrete implementation of a FileCatalog.
00003    Author: Giulio.Eulisse@cern.ch
00004  */
00005 
00006 #include <set>
00007 #include <string>
00008 #include <stdexcept>
00009 #ifndef POOL_TRIVIALFILECATALOG_H
00010 #include "TrivialFileCatalog.h"
00011 #endif
00012 #include "POOLCore/PoolMessageStream.h"
00013 #include "FileCatalog/FCException.h"
00014 
00015 
00016 #include <xercesc/dom/DOM.hpp>
00017 #include <xercesc/parsers/XercesDOMParser.hpp>
00018 #include <xercesc/util/PlatformUtils.hpp>
00019 
00020 #include <cstdlib>
00021 #include <fstream>
00022 #include <iostream>
00023 #include <SealBase/StringList.h>
00024 #include <SealBase/StringOps.h>
00025 #include <SealBase/DebugAids.h>
00026 #include <SealBase/Regexp.h>
00027 
00028 using namespace xercesc;
00029 
00030 int pool::TrivialFileCatalog::s_numberOfInstances = 0;
00031 
00032 inline std::string _toString(const XMLCh *toTranscode)
00033 {
00034     std::string tmp(XMLString::transcode(toTranscode));
00035     return tmp;
00036 }
00037 
00038 inline XMLCh*  _toDOMS(std::string temp){
00039     XMLCh* buff = XMLString::transcode(temp.c_str());    
00040     return  buff;
00041 }
00042 
00043 pool::TrivialFileCatalog::TrivialFileCatalog ()
00044     : m_connectionStatus (false),
00045       m_fileType ("ROOT_All"),
00046       m_destination ("any")
00047 {  
00048     PoolMessageStream trivialLog("TrivialFileCatalog", seal::Msg::Nil);
00049     try { 
00050         trivialLog <<seal::Msg::Info << "Xerces-c initialization Number "
00051           << s_numberOfInstances <<seal::endmsg;
00052         if (s_numberOfInstances==0) 
00053             XMLPlatformUtils::Initialize();  
00054     }
00055     catch (const XMLException& e) {
00056         trivialLog <<seal::Msg::Fatal << "Xerces-c error in initialization \n"
00057               << "Exception message is:  \n"
00058               << _toString(e.getMessage()) << seal::endmsg;
00059         throw(std::runtime_error("Standard pool exception : Fatal Error on pool::TrivialFileCatalog"));
00060     }
00061     ++s_numberOfInstances;
00062     
00063 }
00064 
00065 pool::TrivialFileCatalog::~TrivialFileCatalog ()
00066 {
00067 }
00068 
00069 void
00070 pool::TrivialFileCatalog::parseRule (DOMNode *ruleNode, 
00071                                      ProtocolRules &rules)
00072 {
00073     if (! ruleNode)
00074     {
00075         throw FCTransactionException
00076             ("TrivialFileCatalog::connect",
00077              ":Malformed trivial catalog");             
00078     }
00079             
00080     DOMElement* ruleElement = static_cast<DOMElement *>(ruleNode);          
00081 
00082     if (! ruleElement)
00083     {
00084         throw FCTransactionException
00085             ("TrivialFileCatalog::connect",
00086              ":Malformed trivial catalog");             
00087     }
00088             
00089     std::string protocol 
00090         = _toString (ruleElement->getAttribute (_toDOMS ("protocol")));     
00091     std::string destinationMatchRegexp
00092         = _toString (ruleElement->getAttribute (_toDOMS ("destination-match")));
00093 
00094     if (destinationMatchRegexp.empty ())
00095         destinationMatchRegexp = ".*";
00096 
00097     std::string pathMatchRegexp 
00098         = _toString (ruleElement->getAttribute (_toDOMS ("path-match")));
00099     std::string result 
00100         = _toString (ruleElement->getAttribute (_toDOMS ("result")));
00101     std::string chain 
00102         = _toString (ruleElement->getAttribute (_toDOMS ("chain")));
00103                                             
00104     Rule rule;
00105     rule.pathMatch.setPattern (pathMatchRegexp);
00106     rule.pathMatch.compile ();
00107     rule.destinationMatch.setPattern (destinationMatchRegexp);
00108     rule.destinationMatch.compile ();    
00109     rule.result = result;
00110     rule.chain = chain;
00111     rules[protocol].push_back (rule);    
00112 }
00113 
00114 void
00115 pool::TrivialFileCatalog::connect ()
00116 {
00117     try
00118     {
00119         PoolMessageStream trivialLog("TrivialFileCatalog", seal::Msg::Nil);
00120         trivialLog << seal::Msg::Info << "Connecting to the catalog "
00121                    << m_url << seal::endmsg;
00122 
00123         if (m_url.find ("file:") != std::string::npos)
00124         {
00125             m_url = m_url.erase (0, 
00126                                  m_url.find (":") + 1); 
00127         }       
00128         else
00129         {
00130             throw FCTransactionException
00131                 ("TrivialFileCatalog::connect",
00132                  ": Malformed url for file catalog configuration"); 
00133         }
00134 
00135         seal::StringList tokens = seal::StringOps::split (m_url, "?"); 
00136         m_filename = tokens[0];
00137 
00138         if (tokens.size () == 2)
00139         {
00140             std::string options = tokens[1];
00141             seal::StringList optionTokens = seal::StringOps::split (options, "&");
00142 
00143             for (seal::StringList::iterator option = optionTokens.begin ();
00144                  option != optionTokens.end ();
00145                  option++)
00146             {
00147                 seal::StringList argTokens = seal::StringOps::split (*option, "=") ;
00148                 if (argTokens.size () != 2)
00149                 {
00150                     throw FCTransactionException
00151                         ("TrivialFileCatalog::connect",
00152                          ": Malformed url for file catalog configuration"); 
00153                 }
00154                 
00155                 std::string key = argTokens[0];
00156                 std::string value = argTokens[1];
00157                 
00158                 if (key == "protocol")
00159                 {
00160                     m_protocols = seal::StringOps::split (value, ",");
00161                 }
00162                 else if (key == "destination")
00163                 {
00164                     m_destination = value;
00165                 }
00166             }
00167         }
00168         
00169         if (m_protocols.empty ())
00170             throw FCTransactionException
00171                 ("TrivialFileCatalog::connect",
00172                  ": protocol was not supplied in the contact string"); 
00173                 
00174         std::ifstream configFile;
00175         configFile.open (m_filename.c_str ());
00176         
00177         
00178         trivialLog << seal::Msg::Info
00179                    << "Using catalog configuration " 
00180                    << m_filename << seal::endmsg;
00181         
00182         if (!configFile.good () || !configFile.is_open ())
00183         {
00184             m_transactionsta = 0;
00185             throw FCTransactionException
00186                 ("TrivialFileCatalog::connect",
00187                  ": Unable to open trivial file catalog " + m_filename); 
00188         }
00189         
00190         configFile.close ();
00191         
00192         XercesDOMParser* parser = new XercesDOMParser;     
00193         parser->setValidationScheme(XercesDOMParser::Val_Auto);
00194         parser->setDoNamespaces(false);
00195         parser->parse(m_filename.c_str());      
00196         DOMDocument* doc = parser->getDocument();
00197         ASSERT (doc);
00198         
00199         /* trivialFileCatalog matches the following xml schema
00200            FIXME: write a proper DTD
00201             <storage-mapping>
00202             <lfn-to-pfn protocol="direct" destination-match=".*" 
00203             path-match="lfn/guid match regular expression"
00204             result="/castor/cern.ch/cms/$1"/>
00205             <pfn-to-lfn protocol="srm" 
00206             path-match="lfn/guid match regular expression"
00207             result="$1"/>
00208             </storage-mapping>
00209          */
00210 
00211         /*first of all do the lfn-to-pfn bit*/
00212         {
00213             DOMNodeList *rules =doc->getElementsByTagName(_toDOMS("lfn-to-pfn"));
00214             unsigned int ruleTagsNum  = 
00215                 rules->getLength();
00216         
00217             // FIXME: we should probably use a DTD for checking validity 
00218 
00219             for (unsigned int i=0; i<ruleTagsNum; i++) {
00220                 DOMNode* ruleNode =     rules->item(i);
00221                 parseRule (ruleNode, m_directRules);
00222             }
00223         }
00224         /*Then we handle the pfn-to-lfn bit*/
00225         {
00226             DOMNodeList *rules =doc->getElementsByTagName(_toDOMS("pfn-to-lfn"));
00227             unsigned int ruleTagsNum  = 
00228                 rules->getLength();
00229         
00230             for (unsigned int i=0; i<ruleTagsNum; i++){
00231                 DOMNode* ruleNode =     rules->item(i);
00232                 parseRule (ruleNode, m_inverseRules);
00233             }       
00234         }
00235         
00236         m_transactionsta = 1;
00237     }
00238     catch(std::exception& er)
00239     {
00240         m_transactionsta = 0;   
00241         throw FCconnectionException("TrivialFileCatalog::connect",er.what());
00242     }
00243 }
00244 
00245 void
00246 pool::TrivialFileCatalog::disconnect () const
00247 {
00248         m_transactionsta = 0;       
00249 }
00250 
00251 void
00252 pool::TrivialFileCatalog::start () const
00253 {
00254 }
00255 
00256 void
00257 pool::TrivialFileCatalog::commit (FileCatalog::CommitMode /*cm=FileCatalog::REFRESH*/) const
00258 {
00259 }
00260 
00261 void
00262 pool::TrivialFileCatalog::rollback () const
00263 {
00264     throw FCTransactionException
00265         ("TrivialFileCatalog::rollback",
00266          "Trivial catalogs cannot rollback");
00267 }
00268   
00269 void
00270 pool::TrivialFileCatalog::registerPFN (const std::string& /*pfn*/, 
00271                                        const std::string& /*filetype*/,
00272                                        FileCatalog::FileID& /*fid*/) const
00273 {
00274     throw FCTransactionException
00275         ("TrivialFileCatalog::registerPFN",
00276          "It does not make sense to register PFN for TriviaFileCatalogs");    
00277 }   
00278 
00279 void
00280 pool::TrivialFileCatalog::registerLFN (const std::string& /*pfn*/, 
00281                                        const std::string& /*lfn*/) const
00282 {
00283     throw FCTransactionException
00284         ("TrivialFileCatalog::registerLFN",
00285          "It does not make sense to register LFN for TriviaFileCatalogs");    
00286 }
00287 
00288 void
00289 pool::TrivialFileCatalog::addReplicaPFN (const std::string& /*pfn*/, 
00290                                          const std::string& /*rpf*/) const
00291 {
00292     throw FCTransactionException
00293         ("TrivialFileCatalog::registerLFN",
00294          "It does not make sense to register PFN for TriviaFileCatalogs");    
00295 }
00296 
00297 void
00298 pool::TrivialFileCatalog::addPFNtoGuid (const FileCatalog::FileID& /*guid*/, 
00299                                         const std::string& /*pf*/, 
00300                                         const std::string& /*filetype*/) const
00301 {
00302     throw FCTransactionException
00303         ("TrivialFileCatalog::addPFNtoGuid",
00304          "It does not make sense to register replicas for TriviaFileCatalogs");    
00305 }
00306 
00307 void
00308 pool::TrivialFileCatalog::renamePFN (const std::string& /*pfn*/, 
00309                                      const std::string& /*newpfn*/) const
00310 {
00311     throw FCTransactionException
00312         ("TrivialFileCatalog::renamePFN",
00313          "It does not make sense to rename PFNs for TrivialFileCatalogs");    
00314 }
00315 
00316 void
00317 pool::TrivialFileCatalog::lookupFileByPFN (const std::string & pfn, 
00318                                            FileCatalog::FileID & fid, 
00319                                            std::string& filetype) const
00320 {
00321     filetype = m_fileType;    
00322     fid = "";
00323     std::string tmpPfn = pfn;
00324     
00325     for (seal::StringList::const_iterator protocol = m_protocols.begin ();
00326          protocol != m_protocols.end ();
00327          protocol++)
00328     {
00329         fid = applyRules (m_inverseRules, *protocol, m_destination, false, tmpPfn);
00330         if (! fid.empty ())
00331         {
00332             return;         
00333         }       
00334     }
00335 }
00336 
00337 void
00338 pool::TrivialFileCatalog::lookupFileByLFN (const std::string& lfn, 
00339                                            FileCatalog::FileID& fid) const
00340 {
00341     // return NULL id if the catalog is not connected.
00342     if (m_transactionsta == 0) {
00343         fid = FileCatalog::FileID();
00344         return;
00345     }
00346         
00347     // GUID (FileID) and lfn are the same under TrivialFileCatalog
00348     fid = lfn;    
00349 }
00350 
00351 std::string
00352 replaceWithRegexp (const seal::RegexpMatch matches, 
00353                    const std::string inputString,
00354                    const std::string outputFormat)
00355 {
00356     //std::cerr << "InputString:" << inputString << std::endl;
00357     
00358     char buffer[8];
00359     std::string result = outputFormat;
00360         
00361     for (int i = 1;
00362          i < matches.numMatches ();
00363          i++)
00364     {
00365         // If this is not true, man, we are in trouble...
00366         ASSERT (i < 1000000);
00367         sprintf (buffer, "%i", i);
00368         std::string variableRegexp = std::string ("[$]") + buffer;
00369         std::string matchResult = matches.matchString (inputString, i);
00370         
00371         seal::Regexp sustitutionToken (variableRegexp);
00372         
00373         //std::cerr << "Current match: " << matchResult << std::endl;
00374         
00375         result = seal::StringOps::replace (result, 
00376                                            sustitutionToken, 
00377                                            matchResult);
00378     }
00379     return result;    
00380 }
00381 
00382 
00383 std::string 
00384 pool::TrivialFileCatalog::applyRules (const ProtocolRules& protocolRules,
00385                                       const std::string & protocol,
00386                                       const std::string & destination,
00387                                       bool direct,
00388                                       std::string name) const
00389 {
00390     //std::cerr << "Calling apply rules with protocol: " << protocol << "\n destination: " << destination << "\n " << " on name " << name << std::endl;
00391     
00392     const ProtocolRules::const_iterator rulesIterator = protocolRules.find (protocol);
00393     if (rulesIterator == protocolRules.end ())
00394         return "";
00395     
00396     const Rules &rules=(*(rulesIterator)).second;
00397     
00398     /* Look up for a matching rule*/
00399     for (Rules::const_iterator i = rules.begin ();
00400          i != rules.end ();
00401          i++)
00402     {
00403         if (! i->destinationMatch.exactMatch (destination))
00404             continue;
00405         
00406         if (! i->pathMatch.exactMatch (name))
00407             continue;
00408         
00409         //std::cerr << "Rule " << i->pathMatch.pattern () << "matched! " << std::endl;  
00410         
00411         std::string chain = i->chain;
00412         if ((direct==true) && (chain != ""))
00413         {
00414             name = 
00415                 applyRules (protocolRules, chain, destination, direct, name);           
00416         }
00417             
00418         seal::RegexpMatch matches;
00419         i->pathMatch.match (name, 0, 0, &matches);
00420         
00421         name = replaceWithRegexp (matches, 
00422                                   name,
00423                                   i->result); 
00424             
00425         if ((direct == false) && (chain !=""))
00426         {       
00427             name = 
00428                 applyRules (protocolRules, chain, destination, direct, name);           
00429         }
00430         
00431         return name;
00432     }
00433     return "";
00434 }
00435 
00436 
00437 void
00438 pool::TrivialFileCatalog::lookupBestPFN (const FileCatalog::FileID& fid, 
00439                                          const FileCatalog::FileOpenMode& /*omode*/,
00440                                          const FileCatalog::FileAccessPattern& /*amode*/,
00441                                          std::string& pfn,
00442                                          std::string& filetype) const
00443 {
00444     if (m_transactionsta == 0)
00445         throw FCconnectionException("TrivialFileCatalog::lookupBestPFN",
00446                                     "Catalog not connected");
00447     filetype = m_fileType;    
00448     
00449     pfn = "";
00450     std::string lfn = fid;
00451     
00452     for (seal::StringList::const_iterator protocol = m_protocols.begin ();
00453          protocol != m_protocols.end ();
00454          protocol++)
00455     {
00456         pfn = applyRules (m_directRules, 
00457                           *protocol, 
00458                           m_destination, 
00459                           true, 
00460                           lfn);
00461         if (! pfn.empty ())
00462         {
00463             return;
00464         }
00465     }
00466 } 
00467 
00468 void
00469 pool::TrivialFileCatalog::insertPFN (PFNEntry& /*pentry*/) const
00470 {
00471     throw FCTransactionException
00472         ("TrivialFileCatalog::insertPFN",
00473          "It does not make sense to insert PFNs for TrivialFileCatalogs");    
00474 }
00475 
00476 void
00477 pool::TrivialFileCatalog::insertLFN (LFNEntry& /*lentry*/) const
00478 {
00479     throw FCTransactionException
00480         ("TrivialFileCatalog::insertLFN",
00481          "It does not make sense to insert LFNs for TrivialFileCatalogs");    
00482 }
00483 
00484 void
00485 pool::TrivialFileCatalog::deletePFN (const std::string& /*pfn*/) const
00486 {
00487     throw FCTransactionException
00488         ("TrivialFileCatalog::deletePFN",
00489          "It does not make sense to delete PFNs for TrivialFileCatalogs");    
00490 }
00491 
00492 void
00493 pool::TrivialFileCatalog::deleteLFN (const std::string& /*lfn*/) const
00494 {
00495     throw FCTransactionException
00496         ("TrivialFileCatalog::deleteLFN",
00497          "It does not make sense to delete LFNs for TrivialFileCatalogs");    
00498 }
00499 
00500 void
00501 pool::TrivialFileCatalog::deleteEntry (const FileCatalog::FileID& /*guid*/) const
00502 {
00503     throw FCTransactionException
00504         ("TrivialFileCatalog::deleteEntry",
00505          "It does not make sense to delete GUIDs for TrivialFileCatalogs");    
00506 }
00507 
00508 bool
00509 pool::TrivialFileCatalog::isReadOnly () const
00510 {
00511     return true;    
00512 }
00513  
00514 bool
00515 pool::TrivialFileCatalog::retrievePFN (const std::string& query, 
00516                                        FCBuf<PFNEntry>& buf, 
00517                                        const size_t& /*start*/)
00518 {
00519     if (m_transactionsta == 0)
00520         throw FCconnectionException("TrivialFileCatalog::lookupBestPFN",
00521                                     "Catalog not connected");
00522     // The only query supported is lfn='something' or pfn='something'
00523     // No spaces allowed in something.
00524     seal::Regexp grammar ("(lfname|guid)='(.*)'");
00525     seal::RegexpMatch grammarMatches;
00526     
00527     grammar.match (query, 0, 0, &grammarMatches);
00528     
00529     if (grammarMatches.numMatches () != 3)
00530     {
00531         throw FCTransactionException
00532             ("TrivialFileCatalog::retrievePFN",
00533              "malformed query. the only supported one is lfname='something'"
00534              " or guid='something'");
00535     }
00536     
00537     std::string lfn = grammarMatches.matchString (query, 2);
00538     
00539     for (seal::StringList::iterator protocol = m_protocols.begin ();
00540          protocol != m_protocols.end ();
00541          protocol++)
00542     {
00543         std::string pfn = applyRules (m_directRules, *protocol, m_destination, true, lfn);
00544         if (! pfn.empty ())
00545         {
00546             buf.push_back (PFNEntry(pfn, 
00547                                     lfn, 
00548                                     m_fileType));    
00549             return true;    
00550         }       
00551     }
00552 
00553 
00554     
00555     buf.push_back (PFNEntry(lfn, 
00556                             lfn, 
00557                             m_fileType));    
00558     
00559     return false;    
00560 }
00561 
00562 bool
00563 pool::TrivialFileCatalog::retrieveLFN (const std::string& query, 
00564                                        FCBuf<LFNEntry>& buf, 
00565                                        const size_t& /*start*/)
00566 {    
00567     if (m_transactionsta == 0)
00568         throw FCconnectionException("TrivialFileCatalog::lookupBestPFN",
00569                                     "Catalog not connected");
00570     // The only query supported is lfn='something' or pfn='something'
00571     // No spaces allowed in something.
00572 
00573     seal::Regexp grammar ("(pfname|guid)='(.*)'");
00574     seal::RegexpMatch grammarMatches;
00575     
00576     grammar.match (query, 0, 0, &grammarMatches);
00577     
00578     if (grammarMatches.numMatches () != 3)
00579     {
00580         throw FCTransactionException
00581             ("TrivialFileCatalog::retrieveLFN",
00582              "malformed query. the only supported one is pfname='something'"
00583              " or guid='something'");
00584     }
00585 
00586     std::string selector = grammarMatches.matchString (query, 1);
00587     std::string pfn = grammarMatches.matchString (query, 2);
00588 
00589 
00590     if (selector == "guid")
00591     {
00592         buf.push_back (LFNEntry (pfn,
00593                                  pfn));
00594         return true;    
00595     }
00596     
00597 
00598     for (seal::StringList::iterator protocol = m_protocols.begin ();
00599          protocol != m_protocols.end ();
00600          protocol++)
00601     {
00602         std::string lfn = applyRules (m_inverseRules, *protocol, m_destination, false, pfn);
00603         //      std::cerr << "LFN: " << lfn << std::endl;
00604         
00605         if (! lfn.empty ())
00606         {
00607             buf.push_back (LFNEntry(lfn, 
00608                                     lfn));    
00609             return true;    
00610         }       
00611     }
00612 
00613 
00614     
00615     buf.push_back (LFNEntry(pfn, 
00616                             pfn));    
00617     
00618     return false;    
00619 }
00620 
00621 bool
00622 pool::TrivialFileCatalog::retrieveGuid (const std::string& query, 
00623                                         FCBuf<FileCatalog::FileID>& buf, 
00624                                         const size_t& start)
00625 {   
00626     typedef FCBuf<LFNEntry> Buffer;
00627     
00628     Buffer tmpBuf (10);
00629     bool result = retrieveLFN (query, tmpBuf, start);
00630     std::vector<LFNEntry> tmpVect = tmpBuf.getData ();
00631     
00632     for (std::vector<LFNEntry>::iterator i = tmpVect.begin ();
00633          i != tmpVect.end ();
00634          i++)
00635     {
00636         buf.push_back (i->lfname ());   
00637     }    
00638 
00639     return result;    
00640 }

Generated on Tue Jun 9 17:39:09 2009 for CMSSW by  doxygen 1.5.4