PSEvt/src/Source.cpp

Go to the documentation of this file.
00001 //--------------------------------------------------------------------------
00002 // File and Version Information:
00003 //      $Id: Source.cpp 7815 2014-03-09 07:47:26Z salnikov@SLAC.STANFORD.EDU $
00004 //
00005 // Description:
00006 //      Class Source...
00007 //
00008 // Author List:
00009 //      Andrei Salnikov
00010 //
00011 //------------------------------------------------------------------------
00012 
00013 //-----------------------
00014 // This Class's Header --
00015 //-----------------------
00016 #include "PSEvt/Source.h"
00017 
00018 //-----------------
00019 // C/C++ Headers --
00020 //-----------------
00021 #include <vector>
00022 #include <cassert>
00023 #include <map>
00024 #include <iostream>
00025 #include <boost/algorithm/string/trim.hpp>
00026 #include <boost/algorithm/string/split.hpp>
00027 #include <boost/algorithm/string/predicate.hpp>
00028 #include <boost/lexical_cast.hpp>
00029 
00030 //-------------------------------
00031 // Collaborating Class Headers --
00032 //-------------------------------
00033 #include "MsgLogger/MsgLogger.h"
00034 #include "PSEvt/Exceptions.h"
00035 #include "PSEvt/EventKey.h"
00036 
00037 //-----------------------------------------------------------------------
00038 // Local Macros, Typedefs, Structures, Unions and Forward Declarations --
00039 //-----------------------------------------------------------------------
00040 
00041 namespace {
00042   
00043   const char* logger = "PSEvt::Source";
00044 
00045   // Parse spec tring and return Src or throw
00046   Pds::Src parse(std::string spec);
00047   
00048   std::map<std::string, Pds::DetInfo::Detector> initName2Det();
00049   const std::map<std::string, Pds::DetInfo::Detector> name2det = initName2Det();
00050 
00051   std::map<std::string, Pds::DetInfo::Device> initName2Dev();
00052   const std::map<std::string, Pds::DetInfo::Device> name2dev = initName2Dev();
00053 
00054 }
00055 
00056 //              ----------------------------------------
00057 //              -- Public Function Member Definitions --
00058 //              ----------------------------------------
00059 
00060 namespace PSEvt {
00061 
00062 /**
00063  *  @brief Match for any source.
00064  *  
00065  *  This object will match any source.
00066  */
00067 Source::Source () 
00068   : m_src(Pds::Level::NumberOfLevels)
00069   , m_str()
00070 {
00071 }
00072 
00073 Source::Source (const Pds::Src& src) 
00074   : m_src(src) 
00075   , m_str()
00076 {
00077 } 
00078 
00079 /**
00080  *  @brief Exact match for DetInfo source.
00081  *  
00082  *  This object will match fully-specified DetInfo source.
00083  */
00084 Source::Source(Pds::DetInfo::Detector det, uint32_t detId, Pds::DetInfo::Device dev, uint32_t devId) 
00085   : m_src(Pds::DetInfo(0, det, detId, dev, devId))
00086   , m_str()
00087 {
00088 }
00089 
00090 /**
00091  *  @brief Exact match for BldInfo.
00092  *  
00093  *  This object will match fully-specified BldInfo source.
00094  */
00095 Source::Source(Pds::BldInfo::Type type)
00096   : m_src(Pds::BldInfo(0, type))
00097   , m_str()
00098 {
00099 }
00100 
00101 Source::Source (const std::string& spec)
00102   : m_src(Pds::Src(Pds::Level::NumberOfLevels))
00103   , m_str(spec)
00104 {
00105 }
00106 
00107 Source& 
00108 Source::operator=(const std::string& spec)
00109 {
00110   m_src = Pds::Src();
00111   m_str = spec;
00112   return *this;
00113 }
00114 
00115 /**
00116  *  @brief Match source with Pds::Src object.
00117  */
00118 bool 
00119 Source::SrcMatch::match(const Pds::Src& src) const
00120 {
00121   if (m_src == Pds::Src()) {
00122     
00123     // no-source must match exactly
00124     return src == Pds::Src();
00125     
00126   } else if (m_src.level() == Pds::Level::NumberOfLevels) {
00127     
00128     // any-match matches all
00129     return true;
00130 
00131   } else if (int(src.level()) > Pds::Level::NumberOfLevels) {
00132     
00133     // strange address (probably no-source)
00134     return false;
00135     
00136   } else if (m_src.level() == Pds::Level::Source) {
00137     
00138     // DetInfo match, source must be the same level
00139     if (src.level() != Pds::Level::Source) return false;
00140 
00141     const Pds::DetInfo& minfo = static_cast<const Pds::DetInfo&>(m_src);
00142     const Pds::DetInfo& info = static_cast<const Pds::DetInfo&>(src);
00143     
00144     if (int(minfo.detector()) != 255 and minfo.detector() != info.detector()) return false;
00145     if (int(minfo.device()) != 255 and minfo.device() != info.device()) return false;
00146     if (minfo.detId() != 255 and minfo.detId() != info.detId()) return false;
00147     if (minfo.devId() != 255 and minfo.devId() != info.devId()) return false;
00148     return true;
00149     
00150   } else if (m_src.level() == Pds::Level::Reporter) {
00151 
00152     // BldInfo match, source must be the same level
00153     if (src.level() != Pds::Level::Reporter) return false;
00154 
00155     const Pds::BldInfo& minfo = static_cast<const Pds::BldInfo&>(m_src);
00156     const Pds::BldInfo& info = static_cast<const Pds::BldInfo&>(src);
00157 
00158     if (uint32_t(minfo.type()) != 0xffffffff and minfo.type() != info.type()) return false;
00159     return true;
00160     
00161   } else {
00162     
00163     // ProcInfo match, level can be anything except Source and Reporter
00164     if (src.level() == Pds::Level::Source) return false;
00165     if (src.level() == Pds::Level::Reporter) return false;
00166     
00167     const Pds::ProcInfo& minfo = static_cast<const Pds::ProcInfo&>(m_src);
00168     const Pds::ProcInfo& info = static_cast<const Pds::ProcInfo&>(src);
00169 
00170     if (minfo.ipAddr() != 0xffffffff and minfo.ipAddr() != info.ipAddr()) return false;
00171     return true;
00172 
00173   }
00174   
00175 }
00176 
00177 // Returns true if set of addresses matched by this instance is
00178 // contained entirely in the set of addresses matched by an argument.
00179 bool
00180 Source::SrcMatch::in(const SrcMatch& other) const
00181 {
00182   // if other address is any-source then it contains anything
00183   if (other.src().level() == Pds::Level::NumberOfLevels) return true;
00184 
00185   if (m_src == Pds::Src()) {
00186 
00187     // no-source, other should be no-source or any-source (handled above)
00188     return other.src() == Pds::Src();
00189 
00190   } else if (m_src.level() == Pds::Level::NumberOfLevels) {
00191 
00192     // any-source, other should be any-source as well (handled above)
00193     return false;
00194 
00195   } else if (int(other.src().level()) > Pds::Level::NumberOfLevels) {
00196 
00197     // strange address (probably no-source)
00198     return false;
00199 
00200   } else if (m_src.level() == Pds::Level::Source) {
00201 
00202     // DetInfo match, source must be the same level
00203     if (other.src().level() != Pds::Level::Source) return false;
00204 
00205     const Pds::DetInfo& this_info = static_cast<const Pds::DetInfo&>(m_src);
00206     const Pds::DetInfo& other_info = static_cast<const Pds::DetInfo&>(other.src());
00207 
00208     if (int(other_info.detector()) != 255 and this_info.detector() != other_info.detector()) return false;
00209     if (int(other_info.device()) != 255 and this_info.device() != other_info.device()) return false;
00210     if (other_info.detId() != 255 and this_info.detId() != other_info.detId()) return false;
00211     if (other_info.devId() != 255 and this_info.devId() != other_info.devId()) return false;
00212     return true;
00213 
00214   } else if (m_src.level() == Pds::Level::Reporter) {
00215 
00216     // BldInfo match, source must be the same level
00217     if (other.src().level() != Pds::Level::Reporter) return false;
00218 
00219     const Pds::BldInfo& this_info = static_cast<const Pds::BldInfo&>(m_src);
00220     const Pds::BldInfo& other_info = static_cast<const Pds::BldInfo&>(other.src());
00221 
00222     if (uint32_t(other_info.type()) != 0xffffffff and this_info.type() != other_info.type()) return false;
00223     return true;
00224 
00225   } else {
00226 
00227     // ProcInfo match, level can be anything except Source and Reporter
00228     if (other.src().level() == Pds::Level::Source) return false;
00229     if (other.src().level() == Pds::Level::Reporter) return false;
00230 
00231     const Pds::ProcInfo& this_info = static_cast<const Pds::ProcInfo&>(m_src);
00232     const Pds::ProcInfo& other_info = static_cast<const Pds::ProcInfo&>(other.src());
00233 
00234     if (other_info.ipAddr() != 0xffffffff and this_info.ipAddr() != other_info.ipAddr()) return false;
00235     return true;
00236 
00237   }
00238 
00239 }
00240 
00241 /// Returns true if it is exact match
00242 bool 
00243 Source::SrcMatch::isExact() const
00244 {
00245   if (m_src.level() == Pds::Level::NumberOfLevels) {
00246     // match-any object is not exact
00247     return false;
00248   }
00249   
00250   if (m_src == Pds::Src()) {
00251     // no-source match is exact
00252     return true;
00253   }
00254 
00255   if (m_src.level() == Pds::Level::Source) {
00256     
00257     const Pds::DetInfo& info = static_cast<const Pds::DetInfo&>(m_src);
00258     return info.detector() != 255 and info.device() != 255 and
00259         info.detId() != 255 and info.devId() != 255;
00260     
00261   } else if (m_src.level() == Pds::Level::Reporter) {
00262     
00263     const Pds::BldInfo& info = static_cast<const Pds::BldInfo&>(m_src);
00264     return uint32_t(info.type()) != 0xffffffff;
00265   
00266   } else {
00267     
00268     const Pds::ProcInfo& info = static_cast<const Pds::ProcInfo&>(m_src);
00269     return info.ipAddr() != 0xffffffff;
00270 
00271   }
00272 
00273 }
00274 
00275 // Returns object which can be used to match Src instances
00276 Source::SrcMatch
00277 Source::srcMatch(const AliasMap& amap) const
00278 {
00279   Pds::Src src = m_src;
00280   if (not m_str.empty()) {
00281     // fist check string in alias map
00282     src = amap.src(m_str);
00283     if (src == Pds::Src()) {
00284       // try to parse, it may throw
00285       src = ::parse(m_str);
00286     }
00287   }
00288   return Source::SrcMatch(src);
00289 }
00290 
00291 // Format Source contents.
00292 void
00293 Source::print(std::ostream& out) const
00294 {
00295   if (not m_str.empty()) {
00296     out << m_str;
00297   } else {
00298     out << m_src;
00299   }
00300 }
00301 
00302 } // namespace PSEvt
00303 
00304 
00305 namespace {
00306 
00307   
00308 // Strip type and parentheses from "Type(...)"
00309 std::string
00310 stripType(const std::string& spec, int typeLen)
00311 {
00312   std::string sspec(spec, typeLen);
00313   boost::algorithm::trim(sspec);
00314 
00315   if (sspec.empty()) throw PSEvt::ExceptionSourceFormat(ERR_LOC, spec);
00316   if (sspec[0] != '(') throw PSEvt::ExceptionSourceFormat(ERR_LOC, spec);
00317   
00318   std::string::size_type p2 = sspec.rfind(')');
00319   if (p2 == std::string::npos) {
00320     throw PSEvt::ExceptionSourceFormat(ERR_LOC, spec);
00321   }
00322 
00323   // remove everything after and including (
00324   sspec.erase(p2);
00325   // remove leading (
00326   sspec.erase(0, 1);
00327 
00328   // strip leading/trailing blanks too
00329   boost::algorithm::trim(sspec);
00330   return sspec;
00331 }
00332 
00333 // Parse BldInfo data, may be empty string or a string returned
00334 // from Pds::BldInfo::name()
00335 bool parseBldInfo(std::string spec, Pds::Src *src)
00336 {
00337   MsgLog(logger, debug, "Source::parseBldInfo: spec = '" << spec << "'");
00338 
00339   if (spec.empty()) {
00340     *src = Pds::BldInfo(0, Pds::BldInfo::Type(0xffffffff));
00341     return true;
00342   }
00343 
00344   // try all known BldInfo names
00345   for (int i = 0; i < Pds::BldInfo::NumberOf; ++ i) {
00346     Pds::BldInfo info(0, Pds::BldInfo::Type(i));
00347     if (spec == Pds::BldInfo::name(info)) {
00348       *src = info;
00349       return true;
00350     }
00351   }
00352   
00353   return false;
00354 }
00355 
00356 // Converst string '[Name][.Num]' into pair Name+Number
00357 // Throws boost::bad_lexical_cast if number is not formatted properly
00358 std::pair<std::string, unsigned> splitDetId(const std::string& spec, char sep)
00359 {
00360   std::pair<std::string, unsigned> res(std::string(), 255);
00361   std::string::size_type p1 = spec.find(sep);
00362   if(p1 == std::string::npos) {
00363     res.first = spec;
00364   } else {
00365     res.first = std::string(spec, 0, p1);
00366     std::string idStr = std::string(spec, p1+1);
00367     if (not (idStr.empty() or idStr == "*")) {
00368       res.second = boost::lexical_cast<unsigned>(idStr);
00369     }
00370   }
00371   if (res.first == "*") res.first.clear();
00372   return res;
00373 }
00374 
00375 // Parse DetInfo string, may be empty string or a string returned
00376 // from Pds::BldInfo::name()
00377 bool parseDetInfo(const std::string& spec, Pds::Src *src, char sep1, char sep2)
00378 {
00379   // string cannot be empty here
00380   assert(not spec.empty());
00381   
00382   std::string detSpec;
00383   std::string devSpec;
00384   std::string::size_type p1 = spec.find(sep1);
00385   if(p1 == std::string::npos) {
00386     detSpec = spec;
00387   } else {
00388     detSpec = std::string(spec, 0, p1);
00389     devSpec = std::string(spec, p1+1);
00390   }
00391 
00392   std::pair<std::string, unsigned> detPair;
00393   std::pair<std::string, unsigned> devPair;
00394   try {
00395     detPair = splitDetId(detSpec, sep2);
00396     devPair = splitDetId(devSpec, sep2);
00397   } catch (const boost::bad_lexical_cast& ex) {
00398     return false;
00399   }
00400   
00401   Pds::DetInfo::Detector det = Pds::DetInfo::Detector(255);
00402   Pds::DetInfo::Device dev = Pds::DetInfo::Device(255);
00403   if (not detPair.first.empty()) {
00404     std::map<std::string, Pds::DetInfo::Detector>::const_iterator it = ::name2det.find(detPair.first);
00405     if (it != ::name2det.end()) {
00406       det = it->second;
00407     }
00408     if (det == 255) return false;
00409   }
00410   if (not devPair.first.empty()) {
00411     std::map<std::string, Pds::DetInfo::Device>::const_iterator it = ::name2dev.find(devPair.first);
00412     if (it != ::name2dev.end()) {
00413       dev = it->second;
00414     }
00415     if (dev == 255) return false;
00416   }
00417 
00418   *src = Pds::DetInfo(0, det, detPair.second, dev, devPair.second);
00419   return true;
00420 }
00421 
00422 // Parse DetInfo string, may be empty string or a string returned
00423 // from Pds::BldInfo::name()
00424 bool parseDetInfo(std::string spec, Pds::Src *src)
00425 {
00426   MsgLog(logger, debug, "Source::parseDetInfo: spec = '" << spec << "'");
00427 
00428   if (spec.empty()) {
00429     *src = Pds::DetInfo(0, Pds::DetInfo::Detector(0xff), 0xff, Pds::DetInfo::Device(0xff), 0xff);
00430     return true;
00431   }
00432   
00433   if (parseDetInfo(spec, src, ':', '.')) return true;
00434   if (parseDetInfo(spec, src, '|', '-')) return true;  
00435   return false;
00436 }
00437 
00438 
00439 // Parse ProcInfo string, may be empty string or "NNN.NNN.NNN.NNN"
00440 bool parseProcInfo(std::string spec, Pds::Src *src)
00441 {
00442   MsgLog(logger, debug, "Source::parseProcInfo: spec = '" << spec << "'");
00443 
00444   if (spec.empty()) {
00445     // level can be anything except Source or Reporter
00446     *src = Pds::ProcInfo(Pds::Level::Segment, 0, 0xffffffff);
00447     return true;
00448   }
00449 
00450   std::vector<std::string> octets;
00451   boost::algorithm::split(octets, spec, boost::is_any_of("."));
00452   if (octets.size() != 4) return false;
00453 
00454   uint32_t ip;
00455   try {
00456     
00457     unsigned oct0 = boost::lexical_cast<unsigned>(octets[0]);
00458     unsigned oct1 = boost::lexical_cast<unsigned>(octets[1]);
00459     unsigned oct2 = boost::lexical_cast<unsigned>(octets[2]);
00460     unsigned oct3 = boost::lexical_cast<unsigned>(octets[3]);
00461     if (oct0 > 255 or oct1 > 255 or oct2 > 255 or oct3 > 255) return false;
00462     ip = (oct0 << 24) | (oct1 << 16) | (oct2 << 8) | oct3;
00463     
00464   } catch (const boost::bad_lexical_cast& ex) {
00465     return false;
00466   }
00467   
00468   // level can be anything except Source or Reporter
00469   *src = Pds::ProcInfo(Pds::Level::Segment, 0, ip);
00470   return true;  
00471 }
00472 
00473   
00474 // Parse spec string and return Src or throw
00475 Pds::Src 
00476 parse(std::string spec)
00477 {
00478   // strip leading/trailing blanks
00479   boost::algorithm::trim(spec);
00480 
00481   MsgLog(logger, debug, "Source::parse: spec = '" << spec << "'");
00482 
00483   // empty string means match anything
00484   if (spec.empty()) return Pds::Src(Pds::Level::NumberOfLevels);
00485 
00486   if (boost::algorithm::starts_with(spec, "DetInfo")) {
00487     
00488     Pds::Src src;
00489     if (not parseDetInfo(stripType(spec, 7), &src)) {
00490       throw PSEvt::ExceptionSourceFormat(ERR_LOC, spec);
00491     }
00492     return src;
00493 
00494   } else if (boost::algorithm::starts_with(spec, "BldInfo")) {
00495 
00496     Pds::Src src;
00497     if (not parseBldInfo(stripType(spec, 7), &src)) { 
00498       throw PSEvt::ExceptionSourceFormat(ERR_LOC, spec);
00499     }
00500     return src;
00501     
00502   } else if (boost::algorithm::starts_with(spec, "ProcInfo")) {
00503 
00504     Pds::Src src;
00505     if (not parseProcInfo(stripType(spec, 8), &src)) {
00506       throw PSEvt::ExceptionSourceFormat(ERR_LOC, spec);
00507     }
00508     return src;
00509     
00510   } else {
00511   
00512     Pds::Src src;
00513     if (parseBldInfo(spec, &src)) return src;
00514     if (parseDetInfo(spec, &src)) return src;
00515     throw PSEvt::ExceptionSourceFormat(ERR_LOC, spec);
00516     
00517   }
00518 }
00519 
00520 std::map<std::string, Pds::DetInfo::Detector>
00521 initName2Det()
00522 {
00523   std::map<std::string, Pds::DetInfo::Detector> name2det;
00524   
00525   // add all current names
00526   for(int i = 0; i < Pds::DetInfo::NumDetector; ++ i) {
00527     name2det[Pds::DetInfo::name(Pds::DetInfo::Detector(i))] = Pds::DetInfo::Detector(i);
00528   }
00529 
00530   // add some names which existed in the past
00531   name2det["AmoIms"] = Pds::DetInfo::AmoIms;
00532   name2det["amoIMS"] = Pds::DetInfo::AmoIms;
00533   name2det["AmoPem"] = Pds::DetInfo::AmoGasdet;
00534   name2det["amoGD"] = Pds::DetInfo::AmoGasdet;
00535   name2det["AmoGasdet"] = Pds::DetInfo::AmoGasdet;
00536   name2det["AmoETof"] = Pds::DetInfo::AmoETof;
00537   name2det["amoETOF"] = Pds::DetInfo::AmoETof;
00538   name2det["AmoITof"] = Pds::DetInfo::AmoITof;
00539   name2det["amoITOF"] = Pds::DetInfo::AmoITof;
00540   name2det["AmoMbs"] = Pds::DetInfo::AmoMbes;
00541   name2det["amoMBES"] = Pds::DetInfo::AmoMbes;
00542   name2det["AmoMbes"] = Pds::DetInfo::AmoMbes;
00543   name2det["AmoIis"] = Pds::DetInfo::AmoVmi;
00544   name2det["amoVMI"] = Pds::DetInfo::AmoVmi;
00545   name2det["AmoVMI"] = Pds::DetInfo::AmoVmi;
00546   name2det["AmoVmi"] = Pds::DetInfo::AmoVmi;
00547   name2det["AmoBps"] = Pds::DetInfo::AmoBps;
00548   name2det["amoBPS"] = Pds::DetInfo::AmoBps;
00549   name2det["epicsArch"] = Pds::DetInfo::EpicsArch;
00550 
00551   return name2det;
00552 }
00553 
00554 std::map<std::string, Pds::DetInfo::Device>
00555 initName2Dev()
00556 {
00557   std::map<std::string, Pds::DetInfo::Device> name2dev;
00558 
00559   // add all current names
00560   for(int i = 0; i < Pds::DetInfo::NumDevice; ++ i) {
00561     name2dev[Pds::DetInfo::name(Pds::DetInfo::Device(i))] = Pds::DetInfo::Device(i);
00562   }
00563 
00564   // add some names which existed in the past
00565   name2dev["TM6740"] = Pds::DetInfo::TM6740;
00566 
00567   return name2dev;
00568 }
00569 
00570 }

Generated on 19 Dec 2016 for PSANAclasses by  doxygen 1.4.7