otsdaq  v1_01_02
 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 
18 std::string ots_demangle(const char* name);
19 
20 namespace ots
21 {
22 
24 {
25 
26 public:
27 
28  static const unsigned int INVALID;
29  typedef std::vector<std::vector<std::string> > DataView;
30  typedef DataView::iterator iterator;
31  typedef DataView::const_iterator const_iterator;
32 
33  ConfigurationView (const std::string &name="");
34  virtual ~ConfigurationView (void);
35  ConfigurationView& copy (const ConfigurationView &src, ConfigurationVersion destinationVersion, const std::string &author);
36 
37 
38  void init(void);
39 
40 
41 
42  //==============================================================================
43  template<class T>
44  unsigned int findRow(unsigned int col, const T& value,
45  unsigned int offsetRow=0) const
46  {
47  std::istringstream s(value);
48  return findRow(col,s.str(),offsetRow);
49  }
50  unsigned int findRow (unsigned int col, const std::string& value, unsigned int offsetRow=0) const;
51  //==============================================================================
52  template<class T>
53  unsigned int findRowInGroup(unsigned int col, const T& value,
54  const std::string &groupId, const std::string &childLinkIndex, unsigned int offsetRow=0) const
55  {
56  std::istringstream s(value);
57  return findRowInGroup(col,s.str(),groupId,childLinkIndex,offsetRow);
58  }
59  unsigned int findRowInGroup (unsigned int col, const std::string &value, const std::string &groupId, const std::string &childLinkIndex, unsigned int offsetRow=0) const;
60  unsigned int findCol (const std::string &name) const;
61  unsigned int findColByType (const std::string &type, int startingCol = 0) const;
62 
63  //Getters
64  const std::string& getUniqueStorageIdentifier (void) const;
65  const std::string& getTableName (void) const;
66  const ConfigurationVersion& getVersion (void) const;
67  const std::string& getComment (void) const;
68  const std::string& getAuthor (void) const;
69  const time_t& getCreationTime (void) const;
70  const time_t& getLastAccessTime (void) const;
71  const bool& getLooseColumnMatching (void) const;
72  const unsigned int getSourceColumnSize (void) const;
73  const unsigned int& getSourceColumnMismatch (void) const;
74  const unsigned int& getSourceColumnMissing (void) const;
75  const std::set<std::string>& getSourceColumnNames (void) const;
76  std::set<std::string> getColumnNames (void) const;
77  std::set<std::string> getColumnStorageNames (void) const;
78  std::vector<std::string> getDefaultRowValues (void) const;
79 
80  unsigned int getNumberOfRows (void) const;
81  unsigned int getNumberOfColumns (void) const;
82  const unsigned int getColUID (void) const;
83 
84  //Note: Group link handling should be done in this ConfigurationView class
85  // only by using isEntryInGroup ...
86  // This is so that multiple group handling is consistent
87 private:
88  bool isEntryInGroupCol (const unsigned int &row, const unsigned int &groupCol, const std::string &groupNeedle, std::set<std::string> *groupIDList = 0) const;
89 public:
90  //std::set<std::string /*GroupId*/>
91  std::set<std::string> getSetOfGroupIDs (const std::string &childLinkIndex, unsigned int row = -1) const;
92  bool isEntryInGroup (const unsigned int &row, const std::string &childLinkIndex, const std::string &groupNeedle) const;
93  const bool getChildLink (const unsigned int &col, bool *isGroup, std::pair<unsigned int /*link col*/, unsigned int /*link id col*/> *linkPair) const;
94  const unsigned int getColLinkGroupID (const std::string &childLinkIndex) const;
95  void addRowToGroup (const unsigned int &row, const unsigned int &col, const std::string &groupID, const std::string &colDefault);
96  void removeRowFromGroup (const unsigned int &row, const unsigned int &col, const std::string &groupID);
97 
98  //==============================================================================
99  //Philosophy: force type validation by passing value to fill by reference..
100  // don't allow string to be returned.. (at least not easily)
101  //Since there is no environmental variable that can just be a number they will all be converted no matter what.
102  template<class T>
103  void getValue(T& value, unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const
104  {
105  if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
106  throw std::runtime_error("Invalid row col requested");
107 
108  if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER) //handle numbers
109  {
110  std::string data = convertEnvironmentVariables?convertEnvVariables(theDataView_[row][col]):
111  theDataView_[row][col];
112 
113  if(!isNumber(data))
114  {
115  __SS__ << (data + " is not a number!") << std::endl;
116  __MOUT__ << "\n" << ss.str();
117  throw std::runtime_error(ss.str());
118  }
119 
120  if(typeid(double) == typeid(value))
121  value = strtod(data.c_str(),0);
122  else if(typeid(float) == typeid(value))
123  value = strtof(data.c_str(),0);
124  else if(data.size() > 2 && data[1] == 'x') //assume hex value
125  value = strtol(data.c_str(),0,16);
126  else if(data.size() > 1 && data[0] == 'b') //assume binary value
127  value = strtol(data.substr(1).c_str(),0,2); //skip first 'b' character
128  else
129  value = strtol(data.c_str(),0,10);
130  }
131  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA &&
132  columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
133  (typeid(int) == typeid(value) ||
134  typeid(unsigned int) == typeid(value)))
135  {
136  //if fixed choice type but int is requested
137  // then return index in fixed choice list
138  // (always consider DEFAULT as index 0)
139  //throw error if no match
140 
141  if(theDataView_[row][col] == ViewColumnInfo::DATATYPE_STRING_DEFAULT)
142  value = 0;
143  else
144  {
145  std::vector<std::string> choices = columnsInfo_[col].getDataChoices();
146  for(value=1;value-1<(T)choices.size();++value)
147  if(theDataView_[row][col] == choices[value-1])
148  return; //value has been set to selected choice index, so return
149 
150  __SS__ << "\tInvalid value for column data type: " << columnsInfo_[col].getDataType()
151  << " in configuration " << tableName_
152  << " at column=" << columnsInfo_[col].getName()
153  << " for getValue with type '" << ots_demangle(typeid(value).name())
154  << ".'"
155  << "Attempting to get index of '" << theDataView_[row][col]
156  << " in fixed choice array, but was not found in array. "
157  << "Here are the valid choices:\n";
158  ss << "\t" << ViewColumnInfo::DATATYPE_STRING_DEFAULT << "\n";
159  for(const auto &choice:choices)
160  ss << "\t" << choice << "\n";
161  __MOUT__ << "\n" << ss.str();
162  throw std::runtime_error(ss.str());
163  }
164  }
165  else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING &&
166  typeid(bool) == typeid(value)) //handle bool
167  {
168  if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_ON_OFF)
169  value = (theDataView_[row][col] == ViewColumnInfo::TYPE_VALUE_ON) ? true:false;
170  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_TRUE_FALSE)
171  value = (theDataView_[row][col] == ViewColumnInfo::TYPE_VALUE_TRUE) ? true:false;
172  else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_YES_NO)
173  value = (theDataView_[row][col] == ViewColumnInfo::TYPE_VALUE_YES) ? true:false;
174  }
175  else
176  {
177  if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA)
178  __MOUT_WARN__ << "For column type " << ViewColumnInfo::TYPE_FIXED_CHOICE_DATA
179  << " the only valid numeric types are 'int' and 'unsigned int.'";
180 
181  __SS__ << "\tUnrecognized column data type: " << columnsInfo_[col].getDataType()
182  << " and column type: " << columnsInfo_[col].getType()
183  << ", in configuration " << tableName_
184  << " at column=" << columnsInfo_[col].getName()
185  << " for getValue with type '" << ots_demangle(typeid(value).name())
186  << "'" << std::endl;
187  throw std::runtime_error(ss.str());
188  }
189  }
190  void getValue(std::string &value, unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
191  std::string getValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
192  std::string getEscapedValueAsString(unsigned int row, unsigned int col, bool convertEnvironmentVariables=true) const;
193  bool isURIEncodedCommentTheSame(const std::string &comment) const;
194 
195  const DataView& getDataView (void) const;
196  const std::vector<ViewColumnInfo>& getColumnsInfo (void) const;
197  std::vector<ViewColumnInfo>* getColumnsInfoP(void);
198  const ViewColumnInfo& getColumnInfo (unsigned int column) const;
199 
200  //Setters
201 
202  void setUniqueStorageIdentifier (const std::string &storageUID);
203  void setTableName (const std::string &name );
204  void setComment (const std::string &comment );
205  void setURIEncodedComment (const std::string &uriComment );
206  void setAuthor (const std::string &author );
207  void setCreationTime (time_t t );
208  void setLastAccessTime (time_t t = time(0) );
209  void setLooseColumnMatching (bool setValue );
210 
211  //==============================================================================
212  template<class T>
213  void setVersion (const T &version)
214  {
215  version_ = ConfigurationVersion(version);
216  }
217 
218 
219  //==============================================================================
220  //These two methods check for basic type consistency
221  template<class T>
222  void setValue(const T &value, unsigned int row, unsigned int col)
223  {
224  if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
225  {
226  __SS__ << "Invalid row (" << row << ") col (" << col << ") requested!" << std::endl;
227  throw std::runtime_error(ss.str());
228  }
229 
230  if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_NUMBER)
231  {
232  std::stringstream ss;
233  ss << value;
234  theDataView_[row][col] = ss.str();
235  }
236  else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_TIME &&
237  typeid(time_t) == typeid(value))
238  {
239  //save DATATYPE_TIME as unix timestamp, but get as nice string
240  std::stringstream ss;
241  ss << value;
242  theDataView_[row][col] = ss.str();
243  }
244  else
245  {
246  __SS__ << "\tUnrecognized view data type: " << columnsInfo_[col].getDataType()
247  << " in configuration " << tableName_
248  << " at column=" << columnsInfo_[col].getName()
249  << " for setValue with type '" << ots_demangle(typeid(value).name())
250  << "'" << std::endl;
251  throw std::runtime_error(ss.str());
252  }
253  }
254  void setValue (const std::string &value, unsigned int row, unsigned int col);
255  void setValue (const char *value, unsigned int row, unsigned int col);
256 
257  //Careful: The setValueAsString method is used to set the value without any consistency check with the data type
258  void setValueAsString (const std::string &value, unsigned int row, unsigned int col);
259 
260  //==============================================================================
261  void resizeDataView (unsigned int nRows, unsigned int nCols);
262  int addRow (void); //returns index of added row, always is last row
263  void deleteRow (int r); //returns true on success
264 
265  //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
266 
267 
268  iterator begin (void) {return theDataView_.begin();}
269  iterator end (void) {return theDataView_.end();}
270  const_iterator begin (void) const {return theDataView_.begin();}
271  const_iterator end (void) const {return theDataView_.end();}
272  void reset (void);
273  void print (std::ostream &out = std::cout) const;
274  void printJSON (std::ostream &out = std::cout) const;
275  int fillFromJSON (const std::string &json);
276  int fillFromCSV (const std::string &data, const int &dataOffset = 0, const std::string &author = "") throw(std::runtime_error);
277  bool setURIEncodedValue (const std::string &value, const unsigned int &row, const unsigned int &col);
278 
279  static std::string decodeURIComponent (const std::string& data);
280 
281 private:
282  const unsigned int getOrInitColUID (void);
283  //operator= is purposely undefined and private (DO NOT USE) - should use copy()
284  ConfigurationView& operator= (const ConfigurationView src);
285 
286  // Return "" if there is no conversion
287  std::string convertEnvVariables (const std::string& data) const;
288  bool isNumber (const std::string& s) const;
289 
290  std::string uniqueStorageIdentifier_; //starts empty "", used to implement re-writeable views ("temporary views") in artdaq db
291  std::string tableName_ ; //View name (extensionTableName in xml)
292  ConfigurationVersion version_ ; //Configuration version
293  std::string comment_ ; //Configuration version comment
294  std::string author_ ;
295  time_t creationTime_ ; //used more like "construction"(constructor) time
296  time_t lastAccessTime_ ; //last time the ConfigurationInterface:get() retrieved this view
297  unsigned int colUID_ ; //special column pointers
298  std::map<std::string, unsigned int> colLinkGroupIDs_; //map from child link index to column
299 
300  bool fillWithLooseColumnMatching_;
301  unsigned int sourceColumnMismatchCount_, sourceColumnMissingCount_;
302  std::set<std::string> sourceColumnNames_;
303 
304  std::vector<ViewColumnInfo> columnsInfo_ ;
305  DataView theDataView_ ;
306 };
307 }
308 
309 
310 
311 #endif