otsdaq  v1_01_03
 All Classes Namespaces Functions
ConfigurationView.h
1 #ifndef _ots_ConfigurationView_h_
2 #define _ots_ConfigurationView_h_
3 
4 #include "otsdaq-core/ConfigurationDataFormats/ViewColumnInfo.h"
5 #include "otsdaq-core/MessageFacility/MessageFacility.h"
6 #include "otsdaq-core/Macros/CoutHeaderMacros.h"
7 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationVersion.h"
8 
9 
10 #include <string>
11 #include <typeinfo> // operator typeid
12 #include <iostream>
13 #include <sstream> // std::stringstream, std::stringbuf
14 #include <vector>
15 #include <cassert>
16 #include <stdlib.h>
17 #include <time.h> /* time_t, time, ctime */
18 
19 std::string ots_demangle(const char* name);
20 
21 namespace ots
22 {
23 
25 {
26 
27 public:
28 
29  static const unsigned int INVALID;
30  typedef std::vector<std::vector<std::string> > DataView;
31  typedef DataView::iterator iterator;
32  typedef DataView::const_iterator const_iterator;
33 
34  ConfigurationView (const std::string &name="");
35  virtual ~ConfigurationView (void);
36  ConfigurationView& copy (const ConfigurationView &src, ConfigurationVersion destinationVersion, const std::string &author);
37 
38 
39  void init(void);
40 
41 
42 
43  //==============================================================================
44  template<class T>
45  unsigned int findRow(unsigned int col, const T& value,
46  unsigned int offsetRow=0) const
47  {
48  std::istringstream s(value);
49  return findRow(col,s.str(),offsetRow);
50  }
51  unsigned int findRow (unsigned int col, const std::string& value, unsigned int offsetRow=0) const;
52  //==============================================================================
53  template<class T>
54  unsigned int findRowInGroup(unsigned int col, const T& value,
55  const std::string &groupId, const std::string &childLinkIndex, unsigned int offsetRow=0) const
56  {
57  std::istringstream s(value);
58  return findRowInGroup(col,s.str(),groupId,childLinkIndex,offsetRow);
59  }
60  unsigned int findRowInGroup (unsigned int col, const std::string &value, const std::string &groupId, const std::string &childLinkIndex, unsigned int offsetRow=0) const;
61  unsigned int findCol (const std::string &name) const;
62  unsigned int findColByType (const std::string &type, int startingCol = 0) const;
63 
64  //Getters
65  const std::string& getUniqueStorageIdentifier (void) const;
66  const std::string& getTableName (void) const;
67  const ConfigurationVersion& getVersion (void) const;
68  const std::string& getComment (void) const;
69  const std::string& getAuthor (void) const;
70  const time_t& getCreationTime (void) const;
71  const time_t& getLastAccessTime (void) const;
72  const bool& getLooseColumnMatching (void) const;
73  const unsigned int getDataColumnSize (void) const;
74  const unsigned int& getSourceColumnMismatch (void) const;
75  const unsigned int& getSourceColumnMissing (void) const;
76  const std::set<std::string>& getSourceColumnNames (void) const;
77  std::set<std::string> getColumnNames (void) const;
78  std::set<std::string> getColumnStorageNames (void) const;
79  std::vector<std::string> getDefaultRowValues (void) const;
80 
81  unsigned int getNumberOfRows (void) const;
82  unsigned int getNumberOfColumns (void) const;
83  const unsigned int getColUID (void) const;
84 
85  //Note: Group link handling should be done in this ConfigurationView class
86  // only by using isEntryInGroup ...
87  // This is so that multiple group handling is consistent
88 private:
89  bool isEntryInGroupCol (const unsigned int& row, const unsigned int& groupCol, const std::string& groupNeedle, std::set<std::string>* groupIDList = 0) const;
90 public:
91  //std::set<std::string /*GroupId*/>
92  std::set<std::string> getSetOfGroupIDs (const std::string& childLinkIndex, unsigned int row = -1) const;
93  bool isEntryInGroup (const unsigned int& row, const std::string& childLinkIndex, const std::string& groupNeedle) const;
94  const bool getChildLink (const unsigned int& col, bool& isGroup, std::pair<unsigned int /*link col*/, unsigned int /*link id col*/>& linkPair) const;
95  const unsigned int getColLinkGroupID (const std::string& childLinkIndex) const;
96  void addRowToGroup (const unsigned int& row, const unsigned int& col, const std::string& groupID, const std::string& colDefault);
97  void removeRowFromGroup (const unsigned int& row, const unsigned int& col, const std::string& groupID);
98 
99  //==============================================================================
100  //Philosophy: force type validation by passing value to fill by reference..
101  // don't allow string to be returned.. (at least not easily)
102  //Since there is no environmental variable that can just be a number they will all be converted no matter what.
103  template<class T>
104  void getValue(T& value, unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const
105  {
106  if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
107  {
108  __SS__ << "Invalid row col requested" << std::endl;
109  __MOUT_ERR__ << "\n" << ss.str();
110  throw std::runtime_error(ss.str());
111  }
112 
113  value = validateValueForColumn<T>(theDataView_[row][col],col,convertEnvironmentVariables);
114 //
115 // if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER) //handle numbers
116 // {
117 // std::string data = convertEnvironmentVariables?convertEnvVariables(theDataView_[row][col]):
118 // theDataView_[row][col];
119 //
120 // if(!isNumber(data))
121 // {
122 // __SS__ << (data + " is not a number!") << std::endl;
123 // __MOUT__ << "\n" << ss.str();
124 // throw std::runtime_error(ss.str());
125 // }
126 //
127 // if(typeid(double) == typeid(value))
128 // value = strtod(data.c_str(),0);
129 // else if(typeid(float) == typeid(value))
130 // value = strtof(data.c_str(),0);
131 // else if(data.size() > 2 && data[1] == 'x') //assume hex value
132 // value = strtol(data.c_str(),0,16);
133 // else if(data.size() > 1 && data[0] == 'b') //assume binary value
134 // value = strtol(data.substr(1).c_str(),0,2); //skip first 'b' character
135 // else
136 // value = strtol(data.c_str(),0,10);
137 // }
138 // else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA &&
139 // columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
140 // (typeid(int) == typeid(value) ||
141 // typeid(unsigned int) == typeid(value)))
142 // {
143 // //this case is for if fixed choice type but int is requested
144 // // then return index in fixed choice list
145 // // (always consider DEFAULT as index 0)
146 // //throw error if no match
147 //
148 // if(theDataView_[row][col] == ViewColumnInfo::DATATYPE_STRING_DEFAULT)
149 // value = 0;
150 // else
151 // {
152 // std::vector<std::string> choices = columnsInfo_[col].getDataChoices();
153 // for(value=1;value-1<(T)choices.size();++value)
154 // if(theDataView_[row][col] == choices[value-1])
155 // return; //value has been set to selected choice index, so return
156 //
157 // __SS__ << "\tInvalid value for column data type: " << columnsInfo_[col].getDataType()
158 // << " in configuration " << tableName_
159 // << " at column=" << columnsInfo_[col].getName()
160 // << " for getValue with type '" << ots_demangle(typeid(value).name())
161 // << ".'"
162 // << "Attempting to get index of '" << theDataView_[row][col]
163 // << " in fixed choice array, but was not found in array. "
164 // << "Here are the valid choices:\n";
165 // ss << "\t" << ViewColumnInfo::DATATYPE_STRING_DEFAULT << "\n";
166 // for(const auto &choice:choices)
167 // ss << "\t" << choice << "\n";
168 // __MOUT__ << "\n" << ss.str();
169 // throw std::runtime_error(ss.str());
170 // }
171 // }
172 // else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
173 // typeid(bool) == typeid(value)) //handle bool
174 // {
175 // if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_ON_OFF)
176 // value = (theDataView_[row][col] == ViewColumnInfo::TYPE_VALUE_ON) ? true:false;
177 // else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_TRUE_FALSE)
178 // value = (theDataView_[row][col] == ViewColumnInfo::TYPE_VALUE_TRUE) ? true:false;
179 // else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_YES_NO)
180 // value = (theDataView_[row][col] == ViewColumnInfo::TYPE_VALUE_YES) ? true:false;
181 // }
182 // else
183 // {
184 // if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA)
185 // __MOUT_WARN__ << "For column type " << ViewColumnInfo::TYPE_FIXED_CHOICE_DATA
186 // << " the only valid numeric types are 'int' and 'unsigned int.'";
187 //
188 // __SS__ << "\tUnrecognized column data type: " << columnsInfo_[col].getDataType()
189 // << " and column type: " << columnsInfo_[col].getType()
190 // << ", in configuration " << tableName_
191 // << " at column=" << columnsInfo_[col].getName()
192 // << " for getValue with type '" << ots_demangle(typeid(value).name())
193 // << "'" << std::endl;
194 // throw std::runtime_error(ss.str());
195 // }
196  }
197  //special version of getValue for string type
198  // Note: necessary because types of std::basic_string<char> cause compiler problems if no string specific function
199  void getValue(std::string& value, unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
200 
201  //==============================================================================
202  //validateValueForColumn
203  // validates value against data rules for specified column.
204  // throws exception if invalid.
205  //
206  // on success returns what the value would be for get value
207  template<class T>
208  T validateValueForColumn(const std::string& value, unsigned int col,
209  bool convertEnvironmentVariables=true) const
210  {
211  if(col >= columnsInfo_.size())
212  {
213  __SS__ << "Invalid col requested" << std::endl;
214  __MOUT_ERR__ << "\n" << ss.str();
215  throw std::runtime_error(ss.str());
216  }
217 
218  T retValue;
219 
220  if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER) //handle numbers
221  {
222  std::string data = convertEnvironmentVariables?convertEnvVariables(value):
223  value;
224 
225  if(!isNumber(data))
226  {
227  __SS__ << (data + " is not a number!") << std::endl;
228  __MOUT__ << "\n" << ss.str();
229  throw std::runtime_error(ss.str());
230  }
231 
232  if(typeid(double) == typeid(retValue))
233  retValue = strtod(data.c_str(),0);
234  else if(typeid(float) == typeid(retValue))
235  retValue = strtof(data.c_str(),0);
236  else if(data.size() > 2 && data[1] == 'x') //assume hex value
237  retValue = strtol(data.c_str(),0,16);
238  else if(data.size() > 1 && data[0] == 'b') //assume binary value
239  retValue = strtol(data.substr(1).c_str(),0,2); //skip first 'b' character
240  else
241  retValue = strtol(data.c_str(),0,10);
242  }
243  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA &&
244  columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
245  (typeid(int) == typeid(retValue) ||
246  typeid(unsigned int) == typeid(retValue)))
247  {
248  //this case is for if fixed choice type but int is requested
249  // then return index in fixed choice list
250  // (always consider DEFAULT as index 0)
251  //throw error if no match
252 
253  if(value == ViewColumnInfo::DATATYPE_STRING_DEFAULT)
254  retValue = 0;
255  else
256  {
257  std::vector<std::string> choices = columnsInfo_[col].getDataChoices();
258  for(retValue=1;retValue-1<(T)choices.size();++retValue)
259  if(value == choices[retValue-1])
260  return retValue; //value has been set to selected choice index, so return
261 
262  __SS__ << "\tInvalid value for column data type: " << columnsInfo_[col].getDataType()
263  << " in configuration " << tableName_
264  << " at column=" << columnsInfo_[col].getName()
265  << " for getValue with type '" << ots_demangle(typeid(retValue).name())
266  << ".'"
267  << "Attempting to get index of '" << value
268  << " in fixed choice array, but was not found in array. "
269  << "Here are the valid choices:\n";
270  ss << "\t" << ViewColumnInfo::DATATYPE_STRING_DEFAULT << "\n";
271  for(const auto &choice:choices)
272  ss << "\t" << choice << "\n";
273  __MOUT__ << "\n" << ss.str();
274  throw std::runtime_error(ss.str());
275  }
276  }
277  else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
278  typeid(bool) == typeid(retValue)) //handle bool
279  {
280  if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_ON_OFF)
281  retValue = (value == ViewColumnInfo::TYPE_VALUE_ON) ? true:false;
282  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_TRUE_FALSE)
283  retValue = (value == ViewColumnInfo::TYPE_VALUE_TRUE) ? true:false;
284  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_YES_NO)
285  retValue = (value == ViewColumnInfo::TYPE_VALUE_YES) ? true:false;
286  }
287  else
288  {
289  if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA)
290  __MOUT_WARN__ << "For column type " << ViewColumnInfo::TYPE_FIXED_CHOICE_DATA
291  << " the only valid numeric types are 'int' and 'unsigned int.'";
292 
293  __SS__ << "\tUnrecognized column data type: " << columnsInfo_[col].getDataType()
294  << " and column type: " << columnsInfo_[col].getType()
295  << ", in configuration " << tableName_
296  << " at column=" << columnsInfo_[col].getName()
297  << " for getValue with type '" << ots_demangle(typeid(retValue).name())
298  << "'" << std::endl;
299  throw std::runtime_error(ss.str());
300  }
301 
302  return retValue;
303  } // end validateValueForColumn()
304  //special version of getValue for string type
305  // Note: necessary because types of std::basic_string<char> cause compiler problems if no string specific function
306  std::string validateValueForColumn(const std::string& value, unsigned int col, bool convertEnvironmentVariables=true) const;
307 
308  std::string getValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
309  std::string getEscapedValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
310  bool isURIEncodedCommentTheSame(const std::string &comment) const;
311 
312  const DataView& getDataView (void) const;
313  const std::vector<ViewColumnInfo>& getColumnsInfo (void) const;
314  std::vector<ViewColumnInfo>* getColumnsInfoP(void);
315  const ViewColumnInfo& getColumnInfo (unsigned int column) const;
316 
317  //Setters
318 
319  void setUniqueStorageIdentifier (const std::string &storageUID);
320  void setTableName (const std::string &name );
321  void setComment (const std::string &comment );
322  void setURIEncodedComment (const std::string &uriComment );
323  void setAuthor (const std::string &author );
324  void setCreationTime (time_t t );
325  void setLastAccessTime (time_t t = time(0) );
326  void setLooseColumnMatching (bool setValue );
327 
328  //==============================================================================
329  template<class T>
330  void setVersion (const T &version)
331  {
332  version_ = ConfigurationVersion(version);
333  }
334 
335 
336  //==============================================================================
337  //These two methods check for basic type consistency
338  template<class T>
339  void setValue(const T &value, unsigned int row, unsigned int col)
340  {
341  if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
342  {
343  __SS__ << "Invalid row (" << row << ") col (" << col << ") requested!" << std::endl;
344  throw std::runtime_error(ss.str());
345  }
346 
347  if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER)
348  {
349  std::stringstream ss;
350  ss << value;
351  theDataView_[row][col] = ss.str();
352  }
353  else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_TIME &&
354  typeid(time_t) == typeid(value))
355  {
356  //save DATATYPE_TIME as unix timestamp, but get as nice string
357  std::stringstream ss;
358  ss << value;
359  theDataView_[row][col] = ss.str();
360  }
361  else
362  {
363  __SS__ << "\tUnrecognized view data type: " << columnsInfo_[col].getDataType()
364  << " in configuration " << tableName_
365  << " at column=" << columnsInfo_[col].getName()
366  << " for setValue with type '" << ots_demangle(typeid(value).name())
367  << "'" << std::endl;
368  throw std::runtime_error(ss.str());
369  }
370  }
371  void setValue (const std::string &value, unsigned int row, unsigned int col);
372  void setValue (const char *value, unsigned int row, unsigned int col);
373 
374  //Careful: The setValueAsString method is used to set the value without any consistency check with the data type
375  void setValueAsString (const std::string &value, unsigned int row, unsigned int col);
376 
377  //==============================================================================
378  void resizeDataView (unsigned int nRows, unsigned int nCols);
379  int addRow (const std::string &author = ""); //returns index of added row, always is last row
380  void deleteRow (int r); //returns true on success
381 
382  //Lore did not like this.. wants special access through separate Supervisor for "Database Management" int addColumn(std::string name, std::string viewName, std::string viewType); //returns index of added column, always is last column unless
383 
384 
385  iterator begin (void) {return theDataView_.begin();}
386  iterator end (void) {return theDataView_.end();}
387  const_iterator begin (void) const {return theDataView_.begin();}
388  const_iterator end (void) const {return theDataView_.end();}
389  void reset (void);
390  void print (std::ostream &out = std::cout) const;
391  void printJSON (std::ostream &out = std::cout) const;
392  int fillFromJSON (const std::string &json);
393  int fillFromCSV (const std::string &data, const int &dataOffset = 0, const std::string &author = "") throw(std::runtime_error);
394  bool setURIEncodedValue (const std::string &value, const unsigned int &row, const unsigned int &col, const std::string &author = "");
395 
396  static std::string decodeURIComponent (const std::string& data);
397 
398 private:
399  const unsigned int getOrInitColUID (void);
400  //operator= is purposely undefined and private (DO NOT USE) - should use copy()
401  ConfigurationView& operator= (const ConfigurationView src);
402 
403  // Return "" if there is no conversion
404  std::string convertEnvVariables (const std::string& data) const;
405  bool isNumber (const std::string& s) const;
406 
407  std::string uniqueStorageIdentifier_; //starts empty "", used to implement re-writeable views ("temporary views") in artdaq db
408  std::string tableName_ ; //View name (extensionTableName in xml)
409  ConfigurationVersion version_ ; //Configuration version
410  std::string comment_ ; //Configuration version comment
411  std::string author_ ;
412  time_t creationTime_ ; //used more like "construction"(constructor) time
413  time_t lastAccessTime_ ; //last time the ConfigurationInterface:get() retrieved this view
414  unsigned int colUID_ ; //special column pointers
415  std::map<std::string, unsigned int> colLinkGroupIDs_; //map from child link index to column
416 
417  bool fillWithLooseColumnMatching_;
418  unsigned int sourceColumnMismatchCount_, sourceColumnMissingCount_;
419  std::set<std::string> sourceColumnNames_;
420 
421  std::vector<ViewColumnInfo> columnsInfo_ ;
422  DataView theDataView_ ;
423 };
424 }
425 
426 
427 
428 #endif