00001 #ifndef _ots_ConfigurationView_h_
00002 #define _ots_ConfigurationView_h_
00003
00004 #include "otsdaq-core/ConfigurationDataFormats/ViewColumnInfo.h"
00005 #include "otsdaq-core/MessageFacility/MessageFacility.h"
00006 #include "otsdaq-core/Macros/CoutHeaderMacros.h"
00007 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationVersion.h"
00008
00009
00010 #include <string>
00011 #include <typeinfo>
00012 #include <iostream>
00013 #include <sstream>
00014 #include <vector>
00015 #include <cassert>
00016 #include <stdlib.h>
00017 #include <time.h>
00018
00019 std::string ots_demangle(const char* name);
00020
00021 namespace ots
00022 {
00023
00024 class ConfigurationView
00025 {
00026
00027 public:
00028
00029 static const unsigned int INVALID;
00030 typedef std::vector<std::vector<std::string> > DataView;
00031 typedef DataView::iterator iterator;
00032 typedef DataView::const_iterator const_iterator;
00033
00034 ConfigurationView (const std::string &name="");
00035 virtual ~ConfigurationView (void);
00036 ConfigurationView& copy (const ConfigurationView &src, ConfigurationVersion destinationVersion, const std::string &author);
00037
00038
00039 void init(void);
00040
00041
00042
00043
00044 template<class T>
00045 unsigned int findRow(unsigned int col, const T& value,
00046 unsigned int offsetRow=0) const
00047 {
00048 std::istringstream s(value);
00049 return findRow(col,s.str(),offsetRow);
00050 }
00051 unsigned int findRow (unsigned int col, const std::string& value, unsigned int offsetRow=0) const;
00052
00053 template<class T>
00054 unsigned int findRowInGroup(unsigned int col, const T& value,
00055 const std::string &groupId, const std::string &childLinkIndex, unsigned int offsetRow=0) const
00056 {
00057 std::istringstream s(value);
00058 return findRowInGroup(col,s.str(),groupId,childLinkIndex,offsetRow);
00059 }
00060 unsigned int findRowInGroup (unsigned int col, const std::string &value, const std::string &groupId, const std::string &childLinkIndex, unsigned int offsetRow=0) const;
00061 unsigned int findCol (const std::string &name) const;
00062 unsigned int findColByType (const std::string &type, int startingCol = 0) const;
00063
00064
00065 const std::string& getUniqueStorageIdentifier (void) const;
00066 const std::string& getTableName (void) const;
00067 const ConfigurationVersion& getVersion (void) const;
00068 const std::string& getComment (void) const;
00069 const std::string& getAuthor (void) const;
00070 const time_t& getCreationTime (void) const;
00071 const time_t& getLastAccessTime (void) const;
00072 const bool& getLooseColumnMatching (void) const;
00073 const unsigned int getDataColumnSize (void) const;
00074 const unsigned int& getSourceColumnMismatch (void) const;
00075 const unsigned int& getSourceColumnMissing (void) const;
00076 const std::set<std::string>& getSourceColumnNames (void) const;
00077 std::set<std::string> getColumnNames (void) const;
00078 std::set<std::string> getColumnStorageNames (void) const;
00079 std::vector<std::string> getDefaultRowValues (void) const;
00080
00081 unsigned int getNumberOfRows (void) const;
00082 unsigned int getNumberOfColumns (void) const;
00083 const unsigned int getColUID (void) const;
00084 const unsigned int getColStatus (void) const;
00085
00086
00087
00088
00089 private:
00090 bool isEntryInGroupCol (const unsigned int& row, const unsigned int& groupCol, const std::string& groupNeedle, std::set<std::string>* groupIDList = 0) const;
00091 public:
00092
00093 std::set<std::string> getSetOfGroupIDs (const std::string& childLinkIndex, unsigned int row = -1) const;
00094 bool isEntryInGroup (const unsigned int& row, const std::string& childLinkIndex, const std::string& groupNeedle) const;
00095 const bool getChildLink (const unsigned int& col, bool& isGroup, std::pair<unsigned int /*link col*/, unsigned int /*link id col*/>& linkPair) const;
00096 const unsigned int getColLinkGroupID (const std::string& childLinkIndex) const;
00097 void addRowToGroup (const unsigned int& row, const unsigned int& col, const std::string& groupID);
00098 bool removeRowFromGroup (const unsigned int& row, const unsigned int& col, const std::string& groupID, bool deleteRowIfNoGroupLeft=false);
00099
00100
00101
00102
00103
00104 template<class T>
00105 void getValue(T& value, unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const
00106 {
00107 if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
00108 {
00109 __SS__ << "Invalid row col requested" << std::endl;
00110 __COUT_ERR__ << "\n" << ss.str();
00111 throw std::runtime_error(ss.str());
00112 }
00113
00114 value = validateValueForColumn<T>(theDataView_[row][col],col,convertEnvironmentVariables);
00115 }
00116
00117
00118 void getValue(std::string& value, unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
00119
00120
00121
00122
00123
00124
00125
00126 template<class T>
00127 T validateValueForColumn(const std::string& value, unsigned int col,
00128 bool convertEnvironmentVariables=true) const
00129 {
00130 if(col >= columnsInfo_.size())
00131 {
00132 __SS__ << "Invalid col requested" << std::endl;
00133 __COUT_ERR__ << "\n" << ss.str();
00134 throw std::runtime_error(ss.str());
00135 }
00136
00137 T retValue;
00138
00139 if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER)
00140 {
00141 std::string data = convertEnvironmentVariables?convertEnvVariables(value):
00142 value;
00143
00144 if(!isNumber(data))
00145 {
00146 __SS__ << (data + " is not a number!") << std::endl;
00147 __COUT__ << "\n" << ss.str();
00148 throw std::runtime_error(ss.str());
00149 }
00150
00151 if(typeid(double) == typeid(retValue))
00152 retValue = strtod(data.c_str(),0);
00153 else if(typeid(float) == typeid(retValue))
00154 retValue = strtof(data.c_str(),0);
00155 else if(data.size() > 2 && data[1] == 'x')
00156 retValue = strtol(data.c_str(),0,16);
00157 else if(data.size() > 1 && data[0] == 'b')
00158 retValue = strtol(data.substr(1).c_str(),0,2);
00159 else
00160 retValue = strtol(data.c_str(),0,10);
00161 }
00162 else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA &&
00163 columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
00164 (typeid(int) == typeid(retValue) ||
00165 typeid(unsigned int) == typeid(retValue)))
00166 {
00167
00168
00169
00170
00171
00172 if(value == ViewColumnInfo::DATATYPE_STRING_DEFAULT)
00173 retValue = 0;
00174 else
00175 {
00176 std::vector<std::string> choices = columnsInfo_[col].getDataChoices();
00177
00178
00179
00180
00181
00182 bool skipOne = (choices.size() &&
00183 choices[0].find("arbitraryBool=") == 0);
00184
00185 for(retValue=1 + (skipOne?1:0);retValue-1<(T)choices.size();++retValue)
00186 if(value == choices[retValue-1])
00187 return retValue - (skipOne?1:0);
00188
00189 __SS__ << "\tInvalid value for column data type: " << columnsInfo_[col].getDataType()
00190 << " in configuration " << tableName_
00191 << " at column=" << columnsInfo_[col].getName()
00192 << " for getValue with type '" << ots_demangle(typeid(retValue).name())
00193 << ".'"
00194 << "Attempting to get index of '" << value
00195 << " in fixed choice array, but was not found in array. "
00196 << "Here are the valid choices:\n";
00197 ss << "\t" << ViewColumnInfo::DATATYPE_STRING_DEFAULT << "\n";
00198 for(const auto &choice:choices)
00199 ss << "\t" << choice << "\n";
00200 __COUT__ << "\n" << ss.str();
00201 throw std::runtime_error(ss.str());
00202 }
00203 }
00204 else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
00205 typeid(bool) == typeid(retValue))
00206 {
00207 if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_ON_OFF)
00208 retValue = (value == ViewColumnInfo::TYPE_VALUE_ON) ? true:false;
00209 else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_TRUE_FALSE)
00210 retValue = (value == ViewColumnInfo::TYPE_VALUE_TRUE) ? true:false;
00211 else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_YES_NO)
00212 retValue = (value == ViewColumnInfo::TYPE_VALUE_YES) ? true:false;
00213 }
00214 else
00215 {
00216 if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA)
00217 __COUT_WARN__ << "For column type " << ViewColumnInfo::TYPE_FIXED_CHOICE_DATA
00218 << " the only valid numeric types are 'int' and 'unsigned int.'";
00219
00220 __SS__ << "\tUnrecognized column data type: " << columnsInfo_[col].getDataType()
00221 << " and column type: " << columnsInfo_[col].getType()
00222 << ", in configuration " << tableName_
00223 << " at column=" << columnsInfo_[col].getName()
00224 << " for getValue with type '" << ots_demangle(typeid(retValue).name())
00225 << "'" << std::endl;
00226 throw std::runtime_error(ss.str());
00227 }
00228
00229 return retValue;
00230 }
00231
00232
00233 std::string validateValueForColumn(const std::string& value, unsigned int col, bool convertEnvironmentVariables=true) const;
00234
00235 std::string getValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
00236 std::string getEscapedValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
00237 bool isURIEncodedCommentTheSame(const std::string &comment) const;
00238
00239 const DataView& getDataView (void) const;
00240 const std::vector<ViewColumnInfo>& getColumnsInfo (void) const;
00241 std::vector<ViewColumnInfo>* getColumnsInfoP(void);
00242 const ViewColumnInfo& getColumnInfo (unsigned int column) const;
00243
00244
00245
00246 void setUniqueStorageIdentifier (const std::string &storageUID);
00247 void setTableName (const std::string &name );
00248 void setComment (const std::string &comment );
00249 void setURIEncodedComment (const std::string &uriComment );
00250 void setAuthor (const std::string &author );
00251 void setCreationTime (time_t t );
00252 void setLastAccessTime (time_t t = time(0) );
00253 void setLooseColumnMatching (bool setValue );
00254
00255
00256 template<class T>
00257 void setVersion (const T &version)
00258 {
00259 version_ = ConfigurationVersion(version);
00260 }
00261
00262
00263
00264
00265 template<class T>
00266 void setValue(const T &value, unsigned int row, unsigned int col)
00267 {
00268 if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
00269 {
00270 __SS__ << "Invalid row (" << row << ") col (" << col << ") requested!" << std::endl;
00271 throw std::runtime_error(ss.str());
00272 }
00273
00274 if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER)
00275 {
00276 std::stringstream ss;
00277 ss << value;
00278 theDataView_[row][col] = ss.str();
00279 }
00280 else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_TIME &&
00281 typeid(time_t) == typeid(value))
00282 {
00283
00284 std::stringstream ss;
00285 ss << value;
00286 theDataView_[row][col] = ss.str();
00287 }
00288 else
00289 {
00290 __SS__ << "\tUnrecognized view data type: " << columnsInfo_[col].getDataType()
00291 << " in configuration " << tableName_
00292 << " at column=" << columnsInfo_[col].getName()
00293 << " for setValue with type '" << ots_demangle(typeid(value).name())
00294 << "'" << std::endl;
00295 throw std::runtime_error(ss.str());
00296 }
00297 }
00298 void setValue (const std::string &value, unsigned int row, unsigned int col);
00299 void setValue (const char *value, unsigned int row, unsigned int col);
00300
00301
00302 void setValueAsString (const std::string &value, unsigned int row, unsigned int col);
00303
00304
00305 void resizeDataView (unsigned int nRows, unsigned int nCols);
00306 int addRow (const std::string &author = "", std::string baseNameAutoUID = "");
00307 void deleteRow (int r);
00308
00309
00310
00311
00312 iterator begin (void) {return theDataView_.begin();}
00313 iterator end (void) {return theDataView_.end();}
00314 const_iterator begin (void) const {return theDataView_.begin();}
00315 const_iterator end (void) const {return theDataView_.end();}
00316 void reset (void);
00317 void print (std::ostream &out = std::cout) const;
00318 void printJSON (std::ostream &out = std::cout) const;
00319 int fillFromJSON (const std::string &json);
00320 int fillFromCSV (const std::string &data, const int &dataOffset = 0, const std::string &author = "") throw(std::runtime_error);
00321 bool setURIEncodedValue (const std::string &value, const unsigned int &row, const unsigned int &col, const std::string &author = "");
00322
00323 static std::string decodeURIComponent (const std::string& data);
00324
00325 private:
00326 const unsigned int getOrInitColUID (void);
00327 const unsigned int getOrInitColStatus (void);
00328
00329
00330 ConfigurationView& operator= (const ConfigurationView src);
00331
00332
00333 std::string convertEnvVariables (const std::string& data) const;
00334 bool isNumber (const std::string& s) const;
00335
00336 std::string uniqueStorageIdentifier_;
00337 std::string tableName_ ;
00338 ConfigurationVersion version_ ;
00339 std::string comment_ ;
00340 std::string author_ ;
00341 time_t creationTime_ ;
00342 time_t lastAccessTime_ ;
00343 unsigned int colUID_, colStatus_;
00344 std::map<std::string, unsigned int> colLinkGroupIDs_;
00345
00346 bool fillWithLooseColumnMatching_;
00347 unsigned int sourceColumnMismatchCount_, sourceColumnMissingCount_;
00348 std::set<std::string> sourceColumnNames_;
00349
00350 std::vector<ViewColumnInfo> columnsInfo_ ;
00351 DataView theDataView_ ;
00352 };
00353 }
00354
00355
00356
00357 #endif