otsdaq  v1_01_04
 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  const unsigned int getColStatus (void) const;
85 
86  //Note: Group link handling should be done in this ConfigurationView class
87  // only by using isEntryInGroup ...
88  // This is so that multiple group handling is consistent
89 private:
90  bool isEntryInGroupCol (const unsigned int& row, const unsigned int& groupCol, const std::string& groupNeedle, std::set<std::string>* groupIDList = 0) const;
91 public:
92  //std::set<std::string /*GroupId*/>
93  std::set<std::string> getSetOfGroupIDs (const std::string& childLinkIndex, unsigned int row = -1) const;
94  bool isEntryInGroup (const unsigned int& row, const std::string& childLinkIndex, const std::string& groupNeedle) const;
95  const bool getChildLink (const unsigned int& col, bool& isGroup, std::pair<unsigned int /*link col*/, unsigned int /*link id col*/>& linkPair) const;
96  const unsigned int getColLinkGroupID (const std::string& childLinkIndex) const;
97  void addRowToGroup (const unsigned int& row, const unsigned int& col, const std::string& groupID);//, const std::string& colDefault);
98  bool removeRowFromGroup (const unsigned int& row, const unsigned int& col, const std::string& groupID, bool deleteRowIfNoGroupLeft=false);
99 
100  //==============================================================================
101  //Philosophy: force type validation by passing value to fill by reference..
102  // don't allow string to be returned.. (at least not easily)
103  //Since there is no environmental variable that can just be a number they will all be converted no matter what.
104  template<class T>
105  void getValue(T& value, unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const
106  {
107  if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
108  {
109  __SS__ << "Invalid row col requested" << std::endl;
110  __COUT_ERR__ << "\n" << ss.str();
111  throw std::runtime_error(ss.str());
112  }
113 
114  value = validateValueForColumn<T>(theDataView_[row][col],col,convertEnvironmentVariables);
115  }
116  //special version of getValue for string type
117  // Note: necessary because types of std::basic_string<char> cause compiler problems if no string specific function
118  void getValue(std::string& value, unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
119 
120  //==============================================================================
121  //validateValueForColumn
122  // validates value against data rules for specified column.
123  // throws exception if invalid.
124  //
125  // on success returns what the value would be for get value
126  template<class T>
127  T validateValueForColumn(const std::string& value, unsigned int col,
128  bool convertEnvironmentVariables=true) const
129  {
130  if(col >= columnsInfo_.size())
131  {
132  __SS__ << "Invalid col requested" << std::endl;
133  __COUT_ERR__ << "\n" << ss.str();
134  throw std::runtime_error(ss.str());
135  }
136 
137  T retValue;
138 
139  if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER) //handle numbers
140  {
141  std::string data = convertEnvironmentVariables?convertEnvVariables(value):
142  value;
143 
144  if(!isNumber(data))
145  {
146  __SS__ << (data + " is not a number!") << std::endl;
147  __COUT__ << "\n" << ss.str();
148  throw std::runtime_error(ss.str());
149  }
150 
151  if(typeid(double) == typeid(retValue))
152  retValue = strtod(data.c_str(),0);
153  else if(typeid(float) == typeid(retValue))
154  retValue = strtof(data.c_str(),0);
155  else if(data.size() > 2 && data[1] == 'x') //assume hex value
156  retValue = strtol(data.c_str(),0,16);
157  else if(data.size() > 1 && data[0] == 'b') //assume binary value
158  retValue = strtol(data.substr(1).c_str(),0,2); //skip first 'b' character
159  else
160  retValue = strtol(data.c_str(),0,10);
161  }
162  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA &&
163  columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
164  (typeid(int) == typeid(retValue) ||
165  typeid(unsigned int) == typeid(retValue)))
166  {
167  //this case is for if fixed choice type but int is requested
168  // then return index in fixed choice list
169  // (always consider DEFAULT as index 0)
170  //throw error if no match
171 
172  if(value == ViewColumnInfo::DATATYPE_STRING_DEFAULT)
173  retValue = 0;
174  else
175  {
176  std::vector<std::string> choices = columnsInfo_[col].getDataChoices();
177 
178  // for(const auto& choice: choices)
179  // __COUT__ << "choice " << choice << __E__;
180 
181  //consider arbitrary bool
182  bool skipOne = (choices.size() &&
183  choices[0].find("arbitraryBool=") == 0);
184 
185  for(retValue=1 + (skipOne?1:0);retValue-1<(T)choices.size();++retValue)
186  if(value == choices[retValue-1])
187  return retValue - (skipOne?1:0); //value has been set to selected choice index, so return
188 
189  __SS__ << "\tInvalid value for column data type: " << columnsInfo_[col].getDataType()
190  << " in configuration " << tableName_
191  << " at column=" << columnsInfo_[col].getName()
192  << " for getValue with type '" << ots_demangle(typeid(retValue).name())
193  << ".'"
194  << "Attempting to get index of '" << value
195  << " in fixed choice array, but was not found in array. "
196  << "Here are the valid choices:\n";
197  ss << "\t" << ViewColumnInfo::DATATYPE_STRING_DEFAULT << "\n";
198  for(const auto &choice:choices)
199  ss << "\t" << choice << "\n";
200  __COUT__ << "\n" << ss.str();
201  throw std::runtime_error(ss.str());
202  }
203  }
204  else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
205  typeid(bool) == typeid(retValue)) //handle bool
206  {
207  if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_ON_OFF)
208  retValue = (value == ViewColumnInfo::TYPE_VALUE_ON) ? true:false;
209  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_TRUE_FALSE)
210  retValue = (value == ViewColumnInfo::TYPE_VALUE_TRUE) ? true:false;
211  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_YES_NO)
212  retValue = (value == ViewColumnInfo::TYPE_VALUE_YES) ? true:false;
213  }
214  else
215  {
216  if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA)
217  __COUT_WARN__ << "For column type " << ViewColumnInfo::TYPE_FIXED_CHOICE_DATA
218  << " the only valid numeric types are 'int' and 'unsigned int.'";
219 
220  __SS__ << "\tUnrecognized column data type: " << columnsInfo_[col].getDataType()
221  << " and column type: " << columnsInfo_[col].getType()
222  << ", in configuration " << tableName_
223  << " at column=" << columnsInfo_[col].getName()
224  << " for getValue with type '" << ots_demangle(typeid(retValue).name())
225  << "'" << std::endl;
226  throw std::runtime_error(ss.str());
227  }
228 
229  return retValue;
230  } // end validateValueForColumn()
231  //special version of getValue for string type
232  // Note: necessary because types of std::basic_string<char> cause compiler problems if no string specific function
233  std::string validateValueForColumn(const std::string& value, unsigned int col, bool convertEnvironmentVariables=true) const;
234 
235  std::string getValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
236  std::string getEscapedValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
237  bool isURIEncodedCommentTheSame(const std::string &comment) const;
238 
239  const DataView& getDataView (void) const;
240  const std::vector<ViewColumnInfo>& getColumnsInfo (void) const;
241  std::vector<ViewColumnInfo>* getColumnsInfoP(void);
242  const ViewColumnInfo& getColumnInfo (unsigned int column) const;
243 
244  //Setters
245 
246  void setUniqueStorageIdentifier (const std::string &storageUID);
247  void setTableName (const std::string &name );
248  void setComment (const std::string &comment );
249  void setURIEncodedComment (const std::string &uriComment );
250  void setAuthor (const std::string &author );
251  void setCreationTime (time_t t );
252  void setLastAccessTime (time_t t = time(0) );
253  void setLooseColumnMatching (bool setValue );
254 
255  //==============================================================================
256  template<class T>
257  void setVersion (const T &version)
258  {
259  version_ = ConfigurationVersion(version);
260  }
261 
262 
263  //==============================================================================
264  //These two methods check for basic type consistency
265  template<class T>
266  void setValue(const T &value, unsigned int row, unsigned int col)
267  {
268  if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
269  {
270  __SS__ << "Invalid row (" << row << ") col (" << col << ") requested!" << std::endl;
271  throw std::runtime_error(ss.str());
272  }
273 
274  if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER)
275  {
276  std::stringstream ss;
277  ss << value;
278  theDataView_[row][col] = ss.str();
279  }
280  else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_TIME &&
281  typeid(time_t) == typeid(value))
282  {
283  //save DATATYPE_TIME as unix timestamp, but get as nice string
284  std::stringstream ss;
285  ss << value;
286  theDataView_[row][col] = ss.str();
287  }
288  else
289  {
290  __SS__ << "\tUnrecognized view data type: " << columnsInfo_[col].getDataType()
291  << " in configuration " << tableName_
292  << " at column=" << columnsInfo_[col].getName()
293  << " for setValue with type '" << ots_demangle(typeid(value).name())
294  << "'" << std::endl;
295  throw std::runtime_error(ss.str());
296  }
297  }
298  void setValue (const std::string &value, unsigned int row, unsigned int col);
299  void setValue (const char *value, unsigned int row, unsigned int col);
300 
301  //Careful: The setValueAsString method is used to set the value without any consistency check with the data type
302  void setValueAsString (const std::string &value, unsigned int row, unsigned int col);
303 
304  //==============================================================================
305  void resizeDataView (unsigned int nRows, unsigned int nCols);
306  int addRow (const std::string &author = "", std::string baseNameAutoUID = ""); //returns index of added row, always is last row
307  void deleteRow (int r);
308 
309  //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
310 
311 
312  iterator begin (void) {return theDataView_.begin();}
313  iterator end (void) {return theDataView_.end();}
314  const_iterator begin (void) const {return theDataView_.begin();}
315  const_iterator end (void) const {return theDataView_.end();}
316  void reset (void);
317  void print (std::ostream &out = std::cout) const;
318  void printJSON (std::ostream &out = std::cout) const;
319  int fillFromJSON (const std::string &json);
320  int fillFromCSV (const std::string &data, const int &dataOffset = 0, const std::string &author = "") throw(std::runtime_error);
321  bool setURIEncodedValue (const std::string &value, const unsigned int &row, const unsigned int &col, const std::string &author = "");
322 
323  static std::string decodeURIComponent (const std::string& data);
324 
325 private:
326  const unsigned int getOrInitColUID (void);
327  const unsigned int getOrInitColStatus (void);
328 
329  //operator= is purposely undefined and private (DO NOT USE) - should use copy()
330  ConfigurationView& operator= (const ConfigurationView src);
331 
332  // Return "" if there is no conversion
333  std::string convertEnvVariables (const std::string& data) const;
334  bool isNumber (const std::string& s) const;
335 
336  std::string uniqueStorageIdentifier_; //starts empty "", used to implement re-writeable views ("temporary views") in artdaq db
337  std::string tableName_ ; //View name (extensionTableName in xml)
338  ConfigurationVersion version_ ; //Configuration version
339  std::string comment_ ; //Configuration version comment
340  std::string author_ ;
341  time_t creationTime_ ; //used more like "construction"(constructor) time
342  time_t lastAccessTime_ ; //last time the ConfigurationInterface:get() retrieved this view
343  unsigned int colUID_, colStatus_; //special column pointers
344  std::map<std::string, unsigned int> colLinkGroupIDs_; //map from child link index to column
345 
346  bool fillWithLooseColumnMatching_;
347  unsigned int sourceColumnMismatchCount_, sourceColumnMissingCount_;
348  std::set<std::string> sourceColumnNames_;
349 
350  std::vector<ViewColumnInfo> columnsInfo_ ;
351  DataView theDataView_ ;
352 };
353 }
354 
355 
356 
357 #endif