Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-09-08 03:21:37

0001 #ifndef CondTools_RunInfo_OMSAccess_h
0002 #define CondTools_RunInfo_OMSAccess_h
0003 
0004 #include <string>
0005 #include <stdexcept>
0006 #include <boost/property_tree/ptree.hpp>
0007 #include <boost/property_tree/json_parser.hpp>
0008 #include <boost/date_time/posix_time/posix_time.hpp>
0009 #include <memory>
0010 
0011 namespace cond {
0012 
0013   // implementation details for data extraction from json/ data conversion to build query urls
0014   namespace impl {
0015 
0016     static constexpr const char* const OMS_TIME_FMT = "%Y-%m-%dT%H:%M:%SZ";
0017 
0018     template <typename T, T fun(const std::string&)>
0019     inline T from_string_impl(const std::string& attributeValue, T zero) {
0020       T ret = zero;
0021       if (not attributeValue.empty() && attributeValue != "null") {
0022         ret = fun(attributeValue);
0023       }
0024       return ret;
0025     }
0026 
0027     template <typename T>
0028     inline T from_string(const std::string& attributeValue) {
0029       throw std::invalid_argument("");
0030     }
0031 
0032     template <>
0033     inline std::string from_string(const std::string& attributeValue) {
0034       return std::string(attributeValue);
0035     }
0036 
0037     inline float s_to_f(const std::string& val) { return std::stof(val); }
0038     template <>
0039     inline float from_string(const std::string& attributeValue) {
0040       return from_string_impl<float, &s_to_f>(attributeValue, 0.);
0041     }
0042 
0043     inline int s_to_i(const std::string& val) { return std::stoi(val); }
0044     template <>
0045     inline int from_string(const std::string& attributeValue) {
0046       return from_string_impl<int, &s_to_i>(attributeValue, 0);
0047     }
0048 
0049     inline unsigned long s_to_ul(const std::string& val) { return std::stoul(val); }
0050     template <>
0051     inline unsigned short from_string(const std::string& attributeValue) {
0052       unsigned long int_val = from_string_impl<unsigned long, &s_to_ul>(attributeValue, 0);
0053       return (unsigned short)int_val;
0054     }
0055 
0056     inline boost::posix_time::ptime s_to_time(const std::string& val) {
0057       boost::posix_time::time_input_facet* facet = new boost::posix_time::time_input_facet(OMS_TIME_FMT);
0058       std::stringstream ss;
0059       ss.imbue(std::locale(std::locale(), facet));
0060       ss << val;
0061       boost::posix_time::ptime time;
0062       ss >> time;
0063       return time;
0064     }
0065     template <>
0066     inline boost::posix_time::ptime from_string(const std::string& attributeValue) {
0067       return from_string_impl<boost::posix_time::ptime, &s_to_time>(attributeValue, boost::posix_time::ptime());
0068     }
0069 
0070     template <typename V>
0071     inline std::string to_string(const V& value) {
0072       return std::to_string(value);
0073     }
0074     template <typename V>
0075     inline std::string to_string(const V* value) {
0076       return std::to_string(*value);
0077     }
0078     template <>
0079     inline std::string to_string(const std::string& value) {
0080       return std::string(value);
0081     }
0082     template <>
0083     inline std::string to_string(const char* value) {
0084       return std::string(value);
0085     }
0086     template <>
0087     inline std::string to_string(const boost::posix_time::ptime& value) {
0088       boost::posix_time::time_facet* facet = new boost::posix_time::time_facet();
0089       facet->format(OMS_TIME_FMT);
0090       std::stringstream stream;
0091       stream.imbue(std::locale(std::locale::classic(), facet));
0092       stream << value;
0093       return stream.str();
0094     }
0095 
0096   }  // namespace impl
0097 
0098   // reference of a result set row. it does not own/hold data.
0099   class OMSServiceResultRef {
0100   public:
0101     OMSServiceResultRef() = delete;
0102     OMSServiceResultRef(const boost::property_tree::ptree* row);
0103 
0104     // return true if no attribute is available
0105     bool empty();
0106     // typed getter for single param
0107     template <typename T>
0108     inline T get(const std::string& attributeName) {
0109       return impl::from_string<T>(getAttribute(attributeName));
0110     }
0111     // getter for arrays
0112     template <typename primitive>
0113     std::vector<primitive> getArray(const std::string& attributeName) {
0114       std::vector<primitive> ret;
0115       for (auto& item : m_row->get_child(attributeName)) {
0116         ret.push_back(item.second.get_value<primitive>());
0117       }
0118       return ret;
0119     }
0120 
0121   private:
0122     std::string getAttribute(const std::string& attributeName);
0123     const boost::property_tree::ptree* m_row = nullptr;
0124   };
0125 
0126   // iterator object for result
0127   class OMSServiceResultIterator {
0128   public:
0129     OMSServiceResultIterator() = delete;
0130     OMSServiceResultIterator(boost::property_tree::ptree::const_iterator iter);
0131 
0132     OMSServiceResultRef operator*();
0133     OMSServiceResultIterator& operator++();
0134 
0135     bool operator==(const OMSServiceResultIterator& rhs);
0136     bool operator!=(const OMSServiceResultIterator& rhs);
0137 
0138   private:
0139     boost::property_tree::ptree::const_iterator m_iter;
0140   };
0141 
0142   // container wrapping the query result, based on boost property tree
0143   class OMSServiceResult {
0144   public:
0145     OMSServiceResult();
0146     // basic iterators, to enable the C++11 for loop semantics
0147     OMSServiceResultIterator begin() const;
0148     OMSServiceResultIterator end() const;
0149 
0150     // parse json returned from curl, filling the property tree
0151     size_t parseData(const std::string& data);
0152 
0153     // returns the number of top level elements of the tree ( result set "rows" )
0154     size_t size() const;
0155 
0156     // returns size()==0
0157     bool empty() const;
0158 
0159   private:
0160     boost::property_tree::ptree m_root;
0161     boost::property_tree::ptree* m_data;
0162   };
0163 
0164   // Query object
0165   class OMSServiceQuery {
0166   public:
0167     // comparison operator label, used in query urls
0168     static constexpr const char* const NEQ = "NEQ";
0169     static constexpr const char* const EQ = "EQ";
0170     static constexpr const char* const LT = "LT";
0171     static constexpr const char* const LE = "LE";
0172     static constexpr const char* const GT = "GT";
0173     static constexpr const char* const GE = "GE";
0174     static constexpr const char* const SNULL = "null";
0175 
0176   public:
0177     OMSServiceQuery() = delete;
0178     OMSServiceQuery(const std::string& baseUrl, const std::string& function);
0179 
0180     // functions to restring query output to specific variables
0181     OMSServiceQuery& addOutputVar(const std::string& varName);
0182     OMSServiceQuery& addOutputVars(const std::initializer_list<const char*>& varNames);
0183 
0184     // generic query filter
0185     template <typename T>
0186     inline OMSServiceQuery& filter(const char* cmp, const std::string& varName, const T& value) {
0187       std::stringstream filter;
0188       if (m_filter.empty()) {
0189         filter << "?";
0190         if (!m_limit.empty()) {
0191           m_limit.front() = '&';
0192         }
0193       } else {
0194         filter << m_filter << "&";
0195       }
0196       filter << "filter[" << varName << "][" << cmp << "]=" << impl::to_string(value);
0197       m_filter = filter.str();
0198       return *this;
0199     }
0200     // filters with specific comparison operators
0201     template <typename T>
0202     inline OMSServiceQuery& filterEQ(const std::string& varName, const T& value) {
0203       return filter<T>(EQ, varName, value);
0204     }
0205     template <typename T>
0206     inline OMSServiceQuery& filterNEQ(const std::string& varName, const T& value) {
0207       return filter<T>(NEQ, varName, value);
0208     }
0209     template <typename T>
0210     inline OMSServiceQuery& filterGT(const std::string& varName, const T& value) {
0211       return filter<T>(GT, varName, value);
0212     }
0213     template <typename T>
0214     inline OMSServiceQuery& filterGE(const std::string& varName, const T& value) {
0215       return filter<T>(GE, varName, value);
0216     }
0217     template <typename T>
0218     inline OMSServiceQuery& filterLT(const std::string& varName, const T& value) {
0219       return filter<T>(LT, varName, value);
0220     }
0221     template <typename T>
0222     inline OMSServiceQuery& filterLE(const std::string& varName, const T& value) {
0223       return filter<T>(LE, varName, value);
0224     }
0225     // not null filter
0226     inline OMSServiceQuery& filterNotNull(const std::string& varName) { return filterNEQ(varName, SNULL); }
0227 
0228     // limit for the page size, when unspecified OMS's default limit is 100
0229     OMSServiceQuery& limit(int value);
0230 
0231     // triggers the execution of the query ( calling curl functions )
0232     bool execute();
0233 
0234     // return code from curl
0235     unsigned long status();
0236 
0237     // result from the query. memory allocated for data is owned by the query object itself
0238     OMSServiceResult& result();
0239 
0240     // the url constructed and used for the query
0241     std::string url();
0242 
0243   private:
0244     void addVar(const std::string& varName);
0245 
0246   private:
0247     std::string m_url;
0248     std::string m_filter;
0249     std::string m_limit;
0250     std::string m_varList;
0251     std::unique_ptr<OMSServiceResult> m_result;
0252     unsigned long m_status = 0;
0253   };
0254 
0255   // provides query access to OMS Web services
0256   class OMSService {
0257   public:
0258     OMSService();
0259 
0260     void connect(const std::string& baseUrl);
0261     std::unique_ptr<OMSServiceQuery> query(const std::string& function) const;
0262 
0263   private:
0264     std::string m_baseUrl;
0265   };
0266 }  // namespace cond
0267 
0268 #endif