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