00001 #include "otsdaq-core/ConfigurationDataFormats/ConfigurationView.h"
00002
00003 #include <iostream>
00004 #include <sstream>
00005 #include <time.h>
00006 #include <cstdlib>
00007 #include <regex>
00008
00009 using namespace ots;
00010
00011 #undef __MF_SUBJECT__
00012 #define __MF_SUBJECT__ "ConfigurationView"
00013 #undef __MF_HDR__
00014 #define __MF_HDR__ tableName_ << ":v" << version_ << ":" << __COUT_HDR_FL__
00015
00016 const unsigned int ConfigurationView::INVALID = -1;
00017
00018
00019 ConfigurationView::ConfigurationView(const std::string &name)
00020 : uniqueStorageIdentifier_ (""),
00021 tableName_ (name),
00022 version_ (ConfigurationVersion::INVALID),
00023 comment_ (""),
00024 author_ (""),
00025 creationTime_ (time(0)),
00026 lastAccessTime_ (0),
00027 colUID_ (INVALID),
00028 fillWithLooseColumnMatching_(false),
00029 sourceColumnMismatchCount_ (0),
00030 sourceColumnMissingCount_ (0)
00031 {}
00032
00033
00034 ConfigurationView::~ConfigurationView(void)
00035 {}
00036
00037
00038
00039
00040
00041 ConfigurationView& ConfigurationView::operator=(const ConfigurationView src)
00042 {
00043 __SS__ << "Invalid use of operator=... Should not directly copy a ConfigurationView. Please use ConfigurationView::copy(sourceView,author,comment)";
00044 throw std::runtime_error(ss.str());
00045 }
00046
00047
00048 ConfigurationView& ConfigurationView::copy(const ConfigurationView &src,
00049 ConfigurationVersion destinationVersion,
00050 const std::string &author)
00051 {
00052 tableName_ = src.tableName_;
00053 version_ = destinationVersion;
00054 comment_ = src.comment_;
00055 author_ = author;
00056
00057 lastAccessTime_ = time(0);
00058 columnsInfo_ = src.columnsInfo_;
00059 theDataView_ = src.theDataView_;
00060 sourceColumnNames_ = src.sourceColumnNames_;
00061 init();
00062 return *this;
00063 }
00064
00065
00066
00067
00068
00069
00070
00071
00072 void ConfigurationView::init(void)
00073 {
00074 try
00075 {
00076
00077
00078 std::set<std::string> colNameSet;
00079 std::string capsColName, colName;
00080 for(auto &colInfo: columnsInfo_)
00081 {
00082 colName = colInfo.getStorageName();
00083 if(colName == "COMMENT_DESCRIPTION")
00084 colName = "COMMENT";
00085 capsColName = "";
00086 for(unsigned int i=0;i<colName.size(); ++i)
00087 {
00088 if(colName[i] == '_') continue;
00089 capsColName += colName[i];
00090 }
00091
00092 colNameSet.emplace(capsColName);
00093 }
00094
00095 if(colNameSet.size() != columnsInfo_.size())
00096 {
00097 __SS__ << "Configuration Error:\t" <<
00098 " Columns names must be unique! There are " << columnsInfo_.size() <<
00099 " columns and the unique name count is " << colNameSet.size() << std::endl;
00100 __MOUT_ERR__ << ss.str();
00101
00102 throw std::runtime_error(ss.str());
00103 }
00104
00105 getOrInitColUID();
00106
00107
00108 unsigned int colPos;
00109 if((colPos = findColByType(ViewColumnInfo::TYPE_COMMENT)) != INVALID)
00110 {
00111 if(columnsInfo_[colPos].getName() != "CommentDescription")
00112 {
00113 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_COMMENT <<
00114 " data type column must have name=" <<
00115 "CommentDescription" << std::endl;
00116 __MOUT_ERR__ << ss.str();
00117 throw std::runtime_error(ss.str());
00118 }
00119
00120 if(findColByType(ViewColumnInfo::TYPE_COMMENT,colPos+1) != INVALID)
00121 {
00122 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_COMMENT <<
00123 " data type in column " <<
00124 columnsInfo_[colPos].getName() <<
00125 " is repeated. This is not allowed." << std::endl;
00126 __MOUT_ERR__ << ss.str();
00127 throw std::runtime_error(ss.str());
00128 }
00129
00130 if(colPos != getNumberOfColumns()-3)
00131 {
00132 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_COMMENT <<
00133 " data type column must be 3rd to last (in column " <<
00134 getNumberOfColumns()-3 << ")." << std::endl;
00135 __MOUT_ERR__ << ss.str();
00136 throw std::runtime_error(ss.str());
00137 }
00138 }
00139 else
00140 {
00141 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_COMMENT <<
00142 " data type column " <<" is missing. This is not allowed." << std::endl;
00143 __MOUT_ERR__ << ss.str();
00144 throw std::runtime_error(ss.str());
00145 }
00146
00147
00148 if((colPos = findColByType(ViewColumnInfo::TYPE_AUTHOR)) != INVALID)
00149 {
00150 if(findColByType(ViewColumnInfo::TYPE_AUTHOR,colPos+1) != INVALID)
00151 {
00152 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_AUTHOR <<
00153 " data type in column " <<
00154 columnsInfo_[colPos].getName() <<
00155 " is repeated. This is not allowed." << std::endl;
00156 __MOUT_ERR__ << ss.str();
00157 throw std::runtime_error(ss.str());
00158 }
00159
00160 if(colPos != getNumberOfColumns()-2)
00161 {
00162 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_AUTHOR <<
00163 " data type column must be 2nd to last (in column " <<
00164 getNumberOfColumns()-2 << ")." << std::endl;
00165 __MOUT_ERR__ << ss.str();
00166 throw std::runtime_error(ss.str());
00167 }
00168 }
00169 else
00170 {
00171 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_AUTHOR <<
00172 " data type column " <<" is missing. This is not allowed." << std::endl;
00173 __MOUT_ERR__ << ss.str();
00174 throw std::runtime_error(ss.str());
00175 }
00176
00177
00178 if((colPos = findColByType(ViewColumnInfo::TYPE_TIMESTAMP)) != INVALID)
00179 {
00180 if(findColByType(ViewColumnInfo::TYPE_TIMESTAMP,colPos+1) != INVALID)
00181 {
00182 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_TIMESTAMP <<
00183 " data type in column " <<
00184 columnsInfo_[colPos].getName() << " is repeated. This is not allowed." <<
00185 std::endl;
00186 __MOUT_ERR__ << ss.str();
00187 throw std::runtime_error(ss.str());
00188 }
00189
00190 if(colPos != getNumberOfColumns()-1)
00191 {
00192 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_TIMESTAMP <<
00193 " data type column must be last (in column " <<
00194 getNumberOfColumns()-1 << ")." << std::endl;
00195 __MOUT_ERR__ << ss.str();
00196 throw std::runtime_error(ss.str());
00197 }
00198 }
00199 else
00200 {
00201 __SS__ << "Configuration Error:\t" << ViewColumnInfo::TYPE_TIMESTAMP <<
00202 " data type column " <<" is missing. This is not allowed." << std::endl;
00203 __MOUT_ERR__ << ss.str();
00204 throw std::runtime_error(ss.str());
00205 }
00206
00207
00208
00209
00210 std::set<std::string > uidSet;
00211 for(unsigned int row = 0; row < getNumberOfRows(); ++row)
00212 {
00213 if(uidSet.find(theDataView_[row][colUID_]) != uidSet.end())
00214 {
00215 __SS__ << ("Entries in UID are not unique. Specifically at row=" +
00216 std::to_string(row) + " value=" + theDataView_[row][colUID_])<< std::endl;
00217 __MOUT_ERR__ << ss.str();
00218 throw std::runtime_error(ss.str());
00219 }
00220
00221 if(theDataView_[row][colUID_].size() == 0)
00222 {
00223 __SS__ << "An invalid UID '" << theDataView_[row][colUID_] << "' " <<
00224 " was identified. UIDs must contain at least 1 character." <<
00225 std::endl;
00226 throw std::runtime_error(ss.str());
00227 }
00228
00229 for(unsigned int i=0;i<theDataView_[row][colUID_].size();++i)
00230 if(!(
00231 (theDataView_[row][colUID_][i] >= 'A' && theDataView_[row][colUID_][i] <= 'Z') ||
00232 (theDataView_[row][colUID_][i] >= 'a' && theDataView_[row][colUID_][i] <= 'z') ||
00233 (theDataView_[row][colUID_][i] >= '0' && theDataView_[row][colUID_][i] <= '9') ||
00234 (theDataView_[row][colUID_][i] == '-' || theDataView_[row][colUID_][i] <= '_')
00235 ))
00236 {
00237 __SS__ << "An invalid UID '" << theDataView_[row][colUID_] << "' " <<
00238 " was identified. UIDs must contain only letters, numbers," <<
00239 "dashes, and underscores." << std::endl;
00240 throw std::runtime_error(ss.str());
00241 }
00242
00243 uidSet.insert(theDataView_[row][colUID_]);
00244 }
00245 if(uidSet.size() != getNumberOfRows())
00246 {
00247 __SS__ << "Entries in UID are not unique!" <<
00248 "There are " << getNumberOfRows() <<
00249 " rows and the unique UID count is " << uidSet.size() << std::endl;
00250 __MOUT_ERR__ << ss.str();
00251 throw std::runtime_error(ss.str());
00252 }
00253
00254
00255 colPos = (unsigned int)-1;
00256 while((colPos = findColByType(ViewColumnInfo::TYPE_UNIQUE_DATA,colPos+1)) != INVALID)
00257 {
00258 std::set<std::string > uDataSet;
00259 for(unsigned int row = 0; row < getNumberOfRows(); ++row)
00260 {
00261 if(uDataSet.find(theDataView_[row][colPos]) != uDataSet.end())
00262 {
00263 __SS__ << "Entries in Unique Data column " <<
00264 columnsInfo_[colPos].getName() <<
00265 (" are not unique. Specifically at row=" +
00266 std::to_string(row) + " value=" + theDataView_[row][colPos]) <<
00267 std::endl;
00268 __MOUT_ERR__ << ss.str();
00269 throw std::runtime_error(ss.str());
00270 }
00271 uDataSet.insert(theDataView_[row][colPos]);
00272 }
00273 if(uDataSet.size() != getNumberOfRows())
00274 {
00275 __SS__ << "Entries in Unique Data column " <<
00276 columnsInfo_[colPos].getName() << " are not unique!" <<
00277 "There are " << getNumberOfRows() <<
00278 " rows and the unique data count is " << uDataSet.size() << std::endl;
00279 __MOUT_ERR__ << ss.str();
00280 throw std::runtime_error(ss.str());
00281 }
00282 }
00283
00284 auto rowDefaults = getDefaultRowValues();
00285
00286
00287
00288
00289
00290
00291 std::set<std::string> groupIdIndexes, childLinkIndexes, childLinkIdLabels;
00292 unsigned int groupIdIndexesCount = 0, childLinkIndexesCount = 0, childLinkIdLabelsCount = 0;
00293 for(unsigned int col = 0; col < getNumberOfColumns(); ++col)
00294 {
00295 if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_FIXED_CHOICE_DATA)
00296 {
00297 bool found;
00298 for(unsigned int row = 0; row < getNumberOfRows(); ++row)
00299 {
00300 found = false;
00301
00302 if(theDataView_[row][col] == rowDefaults[col])
00303 continue;
00304
00305 const std::vector<std::string>& theDataChoices =
00306 columnsInfo_[col].getDataChoices();
00307
00308
00309 if(theDataChoices.size() && theDataChoices[0] ==
00310 "arbitraryBool=1")
00311 continue;
00312
00313 for(const auto &choice:theDataChoices)
00314 {
00315 if(theDataView_[row][col] == choice)
00316 {
00317 found = true;
00318 break;
00319 }
00320 }
00321 if(!found)
00322 {
00323 __SS__ << "Configuration Error:\t'" << theDataView_[row][col] << "' in column " <<
00324 columnsInfo_[col].getName() << " is not a valid Fixed Choice option. " <<
00325 "Possible values are as follows: ";
00326
00327 for(unsigned int i = 0; i < columnsInfo_[col].getDataChoices().size(); ++i)
00328 {
00329 if(i) ss << ", ";
00330 ss << columnsInfo_[col].getDataChoices()[i];
00331 }
00332 ss << "." << std::endl;
00333 __MOUT_ERR__ << ss.str();
00334 throw std::runtime_error(ss.str());
00335 }
00336 }
00337 }
00338 else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_ON_OFF)
00339 for(unsigned int row = 0; row < getNumberOfRows(); ++row)
00340 {
00341 if (theDataView_[row][col] == "1" || theDataView_[row][col] == "on" || theDataView_[row][col] == "On" || theDataView_[row][col] == "ON")
00342 theDataView_[row][col] = ViewColumnInfo::TYPE_VALUE_ON;
00343 else if (theDataView_[row][col] == "0" || theDataView_[row][col] == "off" || theDataView_[row][col] == "Off" || theDataView_[row][col] == "OFF")
00344 theDataView_[row][col] = ViewColumnInfo::TYPE_VALUE_OFF;
00345 else
00346 {
00347 __SS__ << "Configuration Error:\t" << theDataView_[row][col] << " in column " <<
00348 columnsInfo_[col].getName() << " is not a valid Type (On/Off) std::string. Possible values are 1, on, On, ON, 0, off, Off, OFF." << std::endl;
00349 __MOUT_ERR__ << ss.str();
00350 throw std::runtime_error(ss.str());
00351 }
00352 }
00353 else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_TRUE_FALSE)
00354 for(unsigned int row = 0; row < getNumberOfRows(); ++row)
00355 {
00356 if (theDataView_[row][col] == "1" || theDataView_[row][col] == "true" || theDataView_[row][col] == "True" || theDataView_[row][col] == "TRUE")
00357 theDataView_[row][col] = ViewColumnInfo::TYPE_VALUE_TRUE;
00358 else if (theDataView_[row][col] == "0" || theDataView_[row][col] == "false" || theDataView_[row][col] == "False" || theDataView_[row][col] == "FALSE")
00359 theDataView_[row][col] = ViewColumnInfo::TYPE_VALUE_FALSE;
00360 else
00361 {
00362 __SS__ << "Configuration Error:\t" << theDataView_[row][col] << " in column " <<
00363 columnsInfo_[col].getName() << " is not a valid Type (True/False) std::string. Possible values are 1, true, True, TRUE, 0, false, False, FALSE." << std::endl;
00364 __MOUT_ERR__ << ss.str();
00365 throw std::runtime_error("Invalid true/false usage");
00366 }
00367 }
00368 else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_YES_NO)
00369 for(unsigned int row = 0; row < getNumberOfRows(); ++row)
00370 {
00371 if (theDataView_[row][col] == "1" || theDataView_[row][col] == "yes" || theDataView_[row][col] == "Yes" || theDataView_[row][col] == "YES")
00372 theDataView_[row][col] = ViewColumnInfo::TYPE_VALUE_YES;
00373 else if (theDataView_[row][col] == "0" || theDataView_[row][col] == "no" || theDataView_[row][col] == "No" || theDataView_[row][col] == "NO")
00374 theDataView_[row][col] = ViewColumnInfo::TYPE_VALUE_NO;
00375 else
00376 {
00377 __SS__ << "Configuration Error:\t" << theDataView_[row][col] << " in column " <<
00378 columnsInfo_[col].getName() << " is not a valid Type (Yes/No) std::string. Possible values are 1, yes, Yes, YES, 0, no, No, NO." << std::endl;
00379 __MOUT_ERR__ << ss.str();
00380 throw std::runtime_error(ss.str());
00381 }
00382 }
00383 else if(columnsInfo_[col].isGroupID())
00384 {
00385 colLinkGroupIDs_[columnsInfo_[col].getChildLinkIndex()] = col;
00386
00387 groupIdIndexes.emplace(columnsInfo_[col].getChildLinkIndex());
00388 ++groupIdIndexesCount;
00389 }
00390 else if(columnsInfo_[col].isChildLink())
00391 {
00392
00393 for(unsigned int row = 0; row < getNumberOfRows(); ++row)
00394 if(theDataView_[row][col] == "NoLink" ||
00395 theDataView_[row][col] == "No_Link" ||
00396 theDataView_[row][col] == "NOLINK" ||
00397 theDataView_[row][col] == "NO_LINK" ||
00398 theDataView_[row][col] == "Nolink" ||
00399 theDataView_[row][col] == "nolink" ||
00400 theDataView_[row][col] == "noLink")
00401 theDataView_[row][col] = ViewColumnInfo::DATATYPE_LINK_DEFAULT;
00402
00403
00404 childLinkIndexes.emplace(columnsInfo_[col].getChildLinkIndex());
00405 ++childLinkIndexesCount;
00406
00407
00408 if(columnsInfo_[col].getDataType() != ViewColumnInfo::DATATYPE_STRING)
00409 {
00410 __SS__ << "Configuration Error:\t" << "Column " << col <<
00411 " with name " << columnsInfo_[col].getName() <<
00412 " is a Child Link column and has an illegal data type of '" <<
00413 columnsInfo_[col].getDataType() <<
00414 "'. The data type for Child Link columns must be " <<
00415 ViewColumnInfo::DATATYPE_STRING << std::endl;
00416 __MOUT_ERR__ << ss.str();
00417 throw std::runtime_error(ss.str());
00418 }
00419
00420 }
00421 else if(columnsInfo_[col].isChildLinkUID() ||
00422 columnsInfo_[col].isChildLinkGroupID())
00423 {
00424
00425 childLinkIdLabels.emplace(columnsInfo_[col].getChildLinkIndex());
00426 ++childLinkIdLabelsCount;
00427
00428
00429 for(unsigned int row = 0; row < getNumberOfRows(); ++row)
00430 if(theDataView_[row][col] == "")
00431 theDataView_[row][col] = rowDefaults[col];
00432
00433 }
00434 }
00435
00436
00437 if(groupIdIndexes.size() != groupIdIndexesCount)
00438 {
00439 __SS__ << ("GroupId Labels are not unique!") <<
00440 "There are " << groupIdIndexesCount <<
00441 " GroupId Labels and the unique count is " << groupIdIndexes.size() << std::endl;
00442 __MOUT_ERR__ << ss.str();
00443 throw std::runtime_error(ss.str());
00444 }
00445 if(childLinkIndexes.size() != childLinkIndexesCount)
00446 {
00447 __SS__ << ("Child Link Labels are not unique!") <<
00448 "There are " << childLinkIndexesCount <<
00449 " Child Link Labels and the unique count is " << childLinkIndexes.size() << std::endl;
00450 __MOUT_ERR__ << ss.str();
00451 throw std::runtime_error(ss.str());
00452 }
00453 if(childLinkIdLabels.size() != childLinkIdLabelsCount)
00454 {
00455 __SS__ << ("Child Link ID Labels are not unique!") <<
00456 "There are " << childLinkIdLabelsCount <<
00457 " Child Link ID Labels and the unique count is " << childLinkIdLabels.size() << std::endl;
00458 __MOUT_ERR__ << ss.str();
00459 throw std::runtime_error(ss.str());
00460 }
00461
00462 }
00463 catch(...)
00464 {
00465 __MOUT__ << "Error occured in ConfigurationView::init() for version=" << version_ << std::endl;
00466 throw;
00467 }
00468 }
00469
00470
00471
00472
00473 void ConfigurationView::getValue(std::string& value, unsigned int row, unsigned int col, bool convertEnvironmentVariables) const
00474 {
00475 if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
00476 throw std::runtime_error("Invalid row col requested");
00477
00478 if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING)
00479 {
00480 value = theDataView_[row][col];
00481 if(convertEnvironmentVariables)
00482 value = convertEnvVariables(value);
00483 }
00484 else if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_TIME)
00485 {
00486 value.resize(30);
00487 time_t timestamp(strtol(theDataView_[row][col].c_str(),0,10));
00488 struct tm tmstruct;
00489 ::localtime_r(×tamp, &tmstruct);
00490 ::strftime(&value[0], 30, "%c %Z", &tmstruct);
00491 value.resize(strlen(value.c_str()));
00492 }
00493 else
00494 {
00495 __SS__ << "\tUnrecognized column data type: " << columnsInfo_[col].getDataType()
00496 << " in configuration " << tableName_
00497 << " at column=" << columnsInfo_[col].getName()
00498 << " for getValue with type '" << ots_demangle(typeid(value).name())
00499 << "'" << std::endl;
00500 throw std::runtime_error(ss.str());
00501 }
00502
00503
00504 }
00505
00506
00507
00508
00509
00510
00511 std::string ConfigurationView::getValueAsString(unsigned int row, unsigned int col,
00512 bool convertEnvironmentVariables) const
00513 {
00514 if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
00515 throw std::runtime_error("Invalid row col requested");
00516
00517
00518 if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_ON_OFF)
00519 {
00520 if (theDataView_[row][col] == "1" || theDataView_[row][col] == "on" || theDataView_[row][col] == "On" || theDataView_[row][col] == "ON")
00521 return ViewColumnInfo::TYPE_VALUE_ON;
00522 else
00523 return ViewColumnInfo::TYPE_VALUE_OFF;
00524 }
00525 else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_TRUE_FALSE)
00526 {
00527 if (theDataView_[row][col] == "1" || theDataView_[row][col] == "true" || theDataView_[row][col] == "True" || theDataView_[row][col] == "TRUE")
00528 return ViewColumnInfo::TYPE_VALUE_TRUE;
00529 else
00530 return ViewColumnInfo::TYPE_VALUE_FALSE;
00531 }
00532 else if(columnsInfo_[col].getType() == ViewColumnInfo::TYPE_YES_NO)
00533 {
00534 if (theDataView_[row][col] == "1" || theDataView_[row][col] == "yes" || theDataView_[row][col] == "Yes" || theDataView_[row][col] == "YES")
00535 return ViewColumnInfo::TYPE_VALUE_YES;
00536 else
00537 return ViewColumnInfo::TYPE_VALUE_NO;
00538 }
00539
00540 return convertEnvironmentVariables?convertEnvVariables(theDataView_[row][col]):
00541 theDataView_[row][col];
00542 }
00543
00544
00545
00546
00547
00548
00549
00550
00551 std::string ConfigurationView::getEscapedValueAsString(unsigned int row, unsigned int col,
00552 bool convertEnvironmentVariables) const
00553 {
00554 std::string val = getValueAsString(row,col,convertEnvironmentVariables);
00555 std::string retVal = "";
00556 retVal.reserve(val.size());
00557 for(unsigned int i=0;i<val.size();++i)
00558 {
00559 if(val[i] == '\n')
00560 retVal += "\\n";
00561 else if(val[i] == '\t')
00562 retVal += "\\t";
00563 else if(val[i] == '\r')
00564 retVal += "\\r";
00565 else
00566 {
00567
00568 if(val[i] == '"' ||
00569 val[i] == '\\')
00570 retVal += '\\';
00571 retVal += val[i];
00572 }
00573 }
00574 return retVal;
00575 }
00576
00577
00578 std::string ConfigurationView::convertEnvVariables(const std::string& data) const
00579 {
00580 std::string converted = data;
00581 if(data.find("${") != std::string::npos)
00582 {
00583 unsigned int begin = data.find("${");
00584 unsigned int end = data.find("}");
00585 std::string envVariable = data.substr(begin+2, end-begin-2);
00586
00587 if(getenv(envVariable.c_str()) != nullptr)
00588 {
00589 return convertEnvVariables(converted.replace(begin,end-begin+1,getenv(envVariable.c_str())));
00590 }
00591 else
00592 throw std::runtime_error("In configuration " + tableName_ + " the environmental variable: " + envVariable + " is not set! Please make sure you set it before continuing!");
00593 }
00594 return converted;
00595 }
00596
00597
00598
00599
00600 void ConfigurationView::setValue(const std::string &value, unsigned int row, unsigned int col)
00601 {
00602 if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
00603 {
00604 __SS__ << "Invalid row (" << row << ") col (" << col << ") requested!" << std::endl;
00605 throw std::runtime_error(ss.str());
00606 }
00607
00608 if(columnsInfo_[col].getDataType() == ViewColumnInfo::DATATYPE_STRING)
00609 theDataView_[row][col] = value;
00610 else
00611 {
00612
00613 __SS__ << "\tUnrecognized column data type: " << columnsInfo_[col].getDataType()
00614 << " in configuration " << tableName_
00615 << " at column=" << columnsInfo_[col].getName()
00616 << " for setValue with type '" << ots_demangle(typeid(value).name())
00617 << "'" << std::endl;
00618 throw std::runtime_error(ss.str());
00619 }
00620 }
00621 void ConfigurationView::setValue(const char *value, unsigned int row, unsigned int col)
00622 { setValue(std::string(value),row,col); }
00623
00624
00625
00626
00627 void ConfigurationView::setValueAsString(const std::string &value, unsigned int row, unsigned int col)
00628 {
00629 if(!(col < columnsInfo_.size() && row < getNumberOfRows()))
00630 {
00631 __SS__ << "Invalid row (" << row << ") col (" << col << ") requested!" << std::endl;
00632 throw std::runtime_error(ss.str());
00633 }
00634
00635 theDataView_[row][col] = value;
00636 }
00637
00638
00639
00640
00641 const unsigned int ConfigurationView::getOrInitColUID (void)
00642 {
00643 if(colUID_ != INVALID) return colUID_;
00644
00645
00646 colUID_ = findColByType(ViewColumnInfo::TYPE_UID);
00647 if(colUID_ == INVALID)
00648 {
00649 __MOUT__ << "Column Types: " << std::endl;
00650 for(unsigned int col=0; col<columnsInfo_.size(); ++col)
00651 std::cout << columnsInfo_[col].getType() << "() " << columnsInfo_[col].getName() << std::endl;
00652 __SS__ << "\tMissing UID Column in table named '" << tableName_ << "'" << std::endl;
00653 __MOUT_ERR__ << "\n" << ss.str() << std::endl;
00654 throw std::runtime_error(ss.str());
00655 }
00656 return colUID_;
00657 }
00658
00659
00660
00661
00662 const unsigned int ConfigurationView::getColUID (void) const
00663 {
00664 if(colUID_ != INVALID) return colUID_;
00665
00666 __MOUT__ << "Column Types: " << std::endl;
00667 for(unsigned int col=0; col<columnsInfo_.size(); ++col)
00668 std::cout << columnsInfo_[col].getType() << "() " << columnsInfo_[col].getName() << std::endl;
00669
00670 __SS__ << ("Missing UID Column in config named " + tableName_ +
00671 ". (Possibly ConfigurationView was just not initialized?" +
00672 "This is the const call so can not alter class members)") << std::endl;
00673 __MOUT_ERR__ << "\n" << ss.str() << std::endl;
00674 throw std::runtime_error(ss.str());
00675 }
00676
00677
00678
00679
00680 void ConfigurationView::addRowToGroup(const unsigned int &row,
00681 const unsigned int &col,
00682 const std::string &groupID,
00683 const std::string &colDefault)
00684 {
00685 if(isEntryInGroupCol(row,col,groupID))
00686 {
00687 __SS__ << "GroupID (" << groupID <<
00688 ") added to row (" << row
00689 << " is already present!" << std::endl;
00690 throw std::runtime_error(ss.str());
00691 }
00692
00693
00694
00695
00696
00697
00698 if(getDataView()[row][col] == "" ||
00699 getDataView()[row][col] == colDefault)
00700 setValue(
00701 groupID,
00702 row,col);
00703 else
00704 setValue(
00705 groupID + " | " + getDataView()[row][col],
00706 row,col);
00707
00708
00709 }
00710
00711
00712
00713
00714 void ConfigurationView::removeRowFromGroup(const unsigned int &row,
00715 const unsigned int &col,
00716 const std::string &groupNeedle)
00717 {
00718 __MOUT__ << "groupNeedle " << groupNeedle << std::endl;
00719 std::set<std::string> groupIDList;
00720 if(!isEntryInGroupCol(row,col,groupNeedle,&groupIDList))
00721 {
00722 __SS__ << "GroupID (" << groupNeedle <<
00723 ") removed from row (" << row
00724 << ") was already removed!" << std::endl;
00725 throw std::runtime_error(ss.str());
00726 }
00727
00728
00729
00730
00731
00732 std::string newValue = "";
00733 unsigned int cnt = 0;
00734 for(const auto & groupID : groupIDList)
00735 {
00736
00737 if(groupID == groupNeedle) continue;
00738
00739 if(cnt) newValue += " | ";
00740 newValue += groupID;
00741 }
00742 setValue(newValue,row,col);
00743
00744
00745 }
00746
00747
00748
00749
00750
00751
00752
00753 bool ConfigurationView::isEntryInGroup(const unsigned int &r,
00754 const std::string &childLinkIndex,
00755 const std::string &groupNeedle) const
00756 {
00757 unsigned int c = getColLinkGroupID(childLinkIndex);
00758
00759 return isEntryInGroupCol(r,c,groupNeedle);
00760 }
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772 bool ConfigurationView::isEntryInGroupCol(const unsigned int &r,
00773 const unsigned int &c, const std::string &groupNeedle,
00774 std::set<std::string> *groupIDList) const
00775 {
00776 unsigned int i=0;
00777 unsigned int j=0;
00778 bool found = false;
00779
00780
00781
00782
00783 for(;j<theDataView_[r][c].size();++j)
00784 if((theDataView_[r][c][j] == ' ' ||
00785 theDataView_[r][c][j] == '|')
00786 && i == j)
00787 ++i;
00788 else if((theDataView_[r][c][j] == ' ' ||
00789 theDataView_[r][c][j] == '|')
00790 && i != j)
00791 {
00792 if(groupIDList) groupIDList->emplace(theDataView_[r][c].substr(i,j-i));
00793
00794
00795
00796 if(groupNeedle == theDataView_[r][c].substr(i,j-i))
00797 {
00798 if(!groupIDList)
00799 return true;
00800 found = true;
00801 }
00802
00803 i = j+1;
00804 }
00805
00806 if(i != j)
00807 {
00808 if(groupIDList) groupIDList->emplace(theDataView_[r][c].substr(i,j-i));
00809
00810
00811
00812 if(groupNeedle == theDataView_[r][c].substr(i,j-i))
00813 return true;
00814 }
00815
00816 return found;
00817 }
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 std::set<std::string> ConfigurationView::getSetOfGroupIDs(const std::string &childLinkIndex,
00828 unsigned int r) const
00829 {
00830 unsigned int c = getColLinkGroupID(childLinkIndex);
00831
00832
00833
00834 std::set<std::string> retSet;
00835
00836 unsigned int i=0;
00837 unsigned int j=0;
00838
00839 if(r != (unsigned int)-1)
00840 {
00841 if(r >= getNumberOfRows())
00842 {
00843 __SS__ << "Invalid row requested!" << std::endl;
00844 throw std::runtime_error(ss.str());
00845 }
00846
00847
00848
00849 for(;j<theDataView_[r][c].size();++j)
00850 if((theDataView_[r][c][j] == ' ' ||
00851 theDataView_[r][c][j] == '|')
00852 && i == j)
00853 ++i;
00854 else if((theDataView_[r][c][j] == ' ' ||
00855 theDataView_[r][c][j] == '|')
00856 && i != j)
00857 {
00858
00859
00860
00861
00862 retSet.emplace(theDataView_[r][c].substr(i,j-i));
00863
00864
00865 i = j+1;
00866 }
00867
00868 if(i != j)
00869 retSet.emplace(theDataView_[r][c].substr(i,j-i));
00870 }
00871 else
00872 {
00873
00874 for(r=0;r<getNumberOfRows();++r)
00875 {
00876 i=0;
00877 j=0;
00878
00879
00880
00881
00882
00883 for(;j<theDataView_[r][c].size();++j)
00884 {
00885
00886
00887 if((theDataView_[r][c][j] == ' ' ||
00888 theDataView_[r][c][j] == '|')
00889 && i == j)
00890 ++i;
00891 else if((theDataView_[r][c][j] == ' ' ||
00892 theDataView_[r][c][j] == '|')
00893 && i != j)
00894 {
00895
00896
00897
00898 retSet.emplace(theDataView_[r][c].substr(i,j-i));
00899
00900
00901 i = j+1;
00902 }
00903 }
00904
00905 if(i != j)
00906 {
00907
00908
00909 retSet.emplace(theDataView_[r][c].substr(i,j-i));
00910 }
00911 }
00912 }
00913
00914 return retSet;
00915 }
00916
00917
00918
00919
00920 const unsigned int ConfigurationView::getColLinkGroupID(const std::string &childLinkIndex) const
00921 {
00922 std::map<std::string, unsigned int>::const_iterator it = colLinkGroupIDs_.find(childLinkIndex);
00923 if(it !=
00924 colLinkGroupIDs_.end())
00925 return it->second;
00926
00927 __MOUT__ << "Existing Column Types: " << std::endl;
00928 for(unsigned int col=0; col<columnsInfo_.size(); ++col)
00929 std::cout << columnsInfo_[col].getType() << "() " << columnsInfo_[col].getName() << std::endl;
00930
00931 __SS__ << ("Missing column with data type " +
00932 (ViewColumnInfo::TYPE_START_GROUP_ID + "-" + childLinkIndex) +
00933 " in config named " + tableName_) << std::endl;
00934 __MOUT_ERR__ << "\n" << ss.str();
00935 throw std::runtime_error(ss.str());
00936 }
00937
00938
00939 unsigned int ConfigurationView::findRow(unsigned int col, const std::string& value, unsigned int offsetRow) const
00940 {
00941 for(unsigned int row=offsetRow; row<theDataView_.size(); ++row)
00942 {
00943 if(theDataView_[row][col] == value)
00944 return row;
00945 }
00946
00947 __SS__ << "\tIn view: " << tableName_
00948 << ", Can't find value=" << value
00949 << " in column named " << columnsInfo_[col].getName()
00950 << " with type=" << columnsInfo_[col].getType()
00951 << std::endl;
00952
00953
00954
00955 throw std::runtime_error(ss.str());
00956 }
00957
00958
00959 unsigned int ConfigurationView::findRowInGroup(unsigned int col, const std::string& value,
00960 const std::string &groupId, const std::string &childLinkIndex, unsigned int offsetRow) const
00961 {
00962 unsigned int groupIdCol = getColLinkGroupID(childLinkIndex);
00963 for(unsigned int row=offsetRow; row<theDataView_.size(); ++row)
00964 {
00965 if(theDataView_[row][col] == value &&
00966 isEntryInGroupCol(row,groupIdCol,groupId))
00967 return row;
00968 }
00969
00970 __SS__ << "\tIn view: " << tableName_ << ", Can't find in group the value=" <<
00971 value << " in column named " <<
00972 columnsInfo_[col].getName() << " with type=" <<
00973 columnsInfo_[col].getType() << " and GroupID: " <<
00974 groupId << " in column " << groupIdCol <<
00975 " with GroupID child link index " << childLinkIndex << std::endl;
00976 __MOUT__ << ss.str();
00977 throw std::runtime_error(ss.str());
00978 }
00979
00980
00981
00982
00983 unsigned int ConfigurationView::findCol(const std::string& name) const
00984 {
00985 for(unsigned int col=0; col<columnsInfo_.size(); ++col)
00986 if(columnsInfo_[col].getName() == name)
00987 return col;
00988
00989 __SS__ << "\tIn view: " << tableName_ <<
00990 ", Can't find column named " << name << std::endl;
00991 throw std::runtime_error(ss.str());
00992 }
00993
00994
00995
00996
00997 unsigned int ConfigurationView::findColByType(const std::string& type, int startingCol) const
00998 {
00999 for(unsigned int col=startingCol; col<columnsInfo_.size(); ++col)
01000 if(columnsInfo_[col].getType() == type)
01001 return col;
01002
01003 return INVALID;
01004 }
01005
01006
01007
01008 const std::string& ConfigurationView::getUniqueStorageIdentifier(void) const
01009 {
01010 return uniqueStorageIdentifier_;
01011 }
01012
01013
01014 const std::string& ConfigurationView::getTableName(void) const
01015 {
01016 return tableName_;
01017 }
01018
01019
01020 const ConfigurationVersion& ConfigurationView::getVersion(void) const
01021 {
01022 return version_;
01023 }
01024
01025
01026 const std::string& ConfigurationView::getComment(void) const
01027 {
01028 return comment_;
01029 }
01030
01031
01032 const std::string& ConfigurationView::getAuthor(void) const
01033 {
01034 return author_;
01035 }
01036
01037
01038 const time_t& ConfigurationView::getCreationTime(void) const
01039 {
01040 return creationTime_;
01041 }
01042
01043
01044 const time_t& ConfigurationView::getLastAccessTime(void) const
01045 {
01046 return lastAccessTime_;
01047 }
01048
01049
01050 const bool& ConfigurationView::getLooseColumnMatching(void) const
01051 {
01052 return fillWithLooseColumnMatching_;
01053 }
01054
01055
01056 const unsigned int ConfigurationView::getSourceColumnSize(void) const
01057 {
01058
01059
01060 if(!getNumberOfRows()) return getNumberOfColumns();
01061 return sourceColumnNames_.size();
01062 }
01063
01064
01065 const unsigned int& ConfigurationView::getSourceColumnMismatch(void) const
01066 {
01067 return sourceColumnMismatchCount_;
01068 }
01069
01070
01071 const unsigned int& ConfigurationView::getSourceColumnMissing(void) const
01072 {
01073 return sourceColumnMissingCount_;
01074 }
01075
01076
01077 const std::set<std::string>& ConfigurationView::getSourceColumnNames(void) const
01078 {
01079
01080 return sourceColumnNames_;
01081 }
01082
01083
01084 std::set<std::string> ConfigurationView::getColumnNames(void) const
01085 {
01086 std::set<std::string> retSet;
01087 for(auto &colInfo: columnsInfo_)
01088 retSet.emplace(colInfo.getName());
01089 return retSet;
01090 }
01091
01092
01093 std::set<std::string> ConfigurationView::getColumnStorageNames(void) const
01094 {
01095 std::set<std::string> retSet;
01096 for(auto &colInfo: columnsInfo_)
01097 retSet.emplace(colInfo.getStorageName());
01098 return retSet;
01099 }
01100
01101
01102 std::vector<std::string> ConfigurationView::getDefaultRowValues(void) const
01103 {
01104 std::vector<std::string> retVec;
01105
01106
01107 for(unsigned int col=0;col<getNumberOfColumns();++col)
01108 retVec.push_back(columnsInfo_[col].getDefaultValue());
01109
01110 return retVec;
01111 }
01112
01113
01114 unsigned int ConfigurationView::getNumberOfRows(void) const
01115 {
01116 return theDataView_.size();
01117 }
01118
01119
01120 unsigned int ConfigurationView::getNumberOfColumns(void) const
01121 {
01122 return columnsInfo_.size();
01123 }
01124
01125
01126 const ConfigurationView::DataView& ConfigurationView::getDataView(void) const
01127 {
01128 return theDataView_;
01129 }
01130
01131
01132
01133
01134
01135
01136
01137
01138 const std::vector<ViewColumnInfo>& ConfigurationView::getColumnsInfo (void) const
01139 {
01140 return columnsInfo_;
01141 }
01142
01143
01144 std::vector<ViewColumnInfo>* ConfigurationView::getColumnsInfoP(void)
01145 {
01146 return &columnsInfo_;
01147 }
01148
01149 const ViewColumnInfo& ConfigurationView::getColumnInfo(unsigned int column) const
01150 {
01151 if(column >= columnsInfo_.size())
01152 {
01153 std::stringstream errMsg;
01154 errMsg << __COUT_HDR_FL__ << "\nCan't find column " << column <<
01155 "\n\n\n\nThe column info is likely missing due to incomplete Configuration View filling.\n\n"
01156 << std::endl;
01157 throw std::runtime_error(errMsg.str().c_str());
01158 }
01159 return columnsInfo_[column];
01160 }
01161
01162
01163
01164 void ConfigurationView::setUniqueStorageIdentifier(const std::string &storageUID)
01165 {
01166 uniqueStorageIdentifier_ = storageUID;
01167 }
01168
01169
01170 void ConfigurationView::setTableName(const std::string &name)
01171 {
01172 tableName_ = name;
01173 }
01174
01175
01176 void ConfigurationView::setComment(const std::string &comment)
01177 {
01178 comment_ = comment;
01179 }
01180
01181
01182 void ConfigurationView::setURIEncodedComment(const std::string &uriComment)
01183 {
01184 comment_ = decodeURIComponent(uriComment);
01185 }
01186
01187
01188 void ConfigurationView::setAuthor(const std::string &author)
01189 {
01190 author_ = author;
01191 }
01192
01193
01194 void ConfigurationView::setCreationTime(time_t t)
01195 {
01196 creationTime_ = t;
01197 }
01198
01199
01200 void ConfigurationView::setLastAccessTime(time_t t)
01201 {
01202 lastAccessTime_ = t;
01203 }
01204
01205
01206 void ConfigurationView::setLooseColumnMatching(bool setValue)
01207 {
01208 fillWithLooseColumnMatching_ = setValue;
01209 }
01210
01211
01212 void ConfigurationView::reset (void)
01213 {
01214 version_ = -1;
01215 comment_ = "";
01216 author_ + "";
01217 columnsInfo_.clear();
01218 theDataView_.clear();
01219 }
01220
01221
01222 void ConfigurationView::print (std::ostream &out) const
01223 {
01224 out << "==============================================================================" << std::endl;
01225 out << "Print: " << tableName_ << " Version: " << version_ << " Comment: " << comment_ <<
01226 " Author: " << author_ << " Creation Time: " << ctime(&creationTime_) << std::endl;
01227 out << "\t\tNumber of Cols " << getNumberOfColumns() << std::endl;
01228 out << "\t\tNumber of Rows " << getNumberOfRows() << std::endl;
01229
01230 out << "Columns:\t";
01231 for(int i=0;i<(int)columnsInfo_.size();++i)
01232 out << i << ":" << columnsInfo_[i].getName() << ":" << columnsInfo_[i].getStorageName() << ":" << columnsInfo_[i].getDataType() << "\t ";
01233 out << std::endl;
01234
01235 out << "Rows:" << std::endl;
01236 int num;
01237 std::string val;
01238 for(int r=0;r<(int)getNumberOfRows();++r)
01239 {
01240 out << r << ":\t";
01241 for(int c=0;c<(int)getNumberOfColumns();++c)
01242 {
01243 out << c << ":";
01244 out << theDataView_[r][c];
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257 out << "\t\t";
01258 }
01259 out << std::endl;
01260 }
01261 }
01262
01263
01264
01265 void ConfigurationView::printJSON (std::ostream &out) const
01266 {
01267 out << "{\n";
01268 out << "\"NAME\" : \"" << tableName_ << "\",\n";
01269
01270
01271
01272 out << "\"COMMENT\" : ";
01273
01274
01275 std::string val;
01276 val = comment_;
01277 out << "\"";
01278 for(unsigned int i=0;i<val.size();++i)
01279 {
01280
01281 if(val[i] == '\n')
01282 out << "\\n";
01283 else if(val[i] == '\t')
01284 out << "\\t";
01285 else if(val[i] == '\r')
01286 out << "\\r";
01287 else
01288 {
01289
01290 if(val[i] == '"' ||
01291 val[i] == '\\')
01292 out << '\\';
01293 out << val[i];
01294 }
01295 }
01296 out << "\",\n";
01297
01298 out << "\"AUTHOR\" : \"" << author_ << "\",\n";
01299 out << "\"CREATION_TIME\" : " << creationTime_ << ",\n";
01300
01301
01302
01303
01304
01305
01306 out << "\"COL_TYPES\" : {\n";
01307 for(int c=0;c<(int)getNumberOfColumns();++c)
01308 {
01309 out << "\t\t\"" << columnsInfo_[c].getStorageName() << "\" : ";
01310 out << "\"" << columnsInfo_[c].getDataType() << "\"";
01311 if(c+1 < (int)getNumberOfColumns())
01312 out << ",";
01313 out << "\n";
01314 }
01315 out << "},\n";
01316
01317 out << "\"DATA_SET\" : [\n";
01318 int num;
01319 for(int r=0;r<(int)getNumberOfRows();++r)
01320 {
01321 out << "\t{\n";
01322 for(int c=0;c<(int)getNumberOfColumns();++c)
01323 {
01324 out << "\t\t\"" << columnsInfo_[c].getStorageName() << "\" : ";
01325
01326 out << "\"" << getEscapedValueAsString(r,c,false) << "\"";
01327
01328 if(c+1 < (int)getNumberOfColumns())
01329 out << ",";
01330 out << "\n";
01331 }
01332 out << "\t}";
01333 if(r+1 < (int)getNumberOfRows())
01334 out << ",";
01335 out << "\n";
01336 }
01337 out << "]\n";
01338
01339 out << "}";
01340 }
01341
01342
01343
01344
01345 std::string restoreJSONStringEntities(const std::string &str)
01346 {
01347 unsigned int sz = str.size();
01348 if(!sz) return "";
01349
01350 std::stringstream retStr;
01351 unsigned int i=0;
01352 for(;i<sz-1;++i)
01353 {
01354 if(str[i] == '\\')
01355 switch(str[i+1])
01356 {
01357 case 'n':
01358 retStr << '\n'; ++i; break;
01359 case '"':
01360 retStr << '"'; ++i; break;
01361 case 't':
01362 retStr << '\t'; ++i; break;
01363 case 'r':
01364 retStr << '\r'; ++i; break;
01365 case '\\':
01366 retStr << '\\'; ++i; break;
01367 default:
01368 retStr << str[i];
01369 }
01370 else
01371 retStr << str[i];
01372 }
01373 if(i == sz-1)
01374 retStr << str[sz-1];
01375
01376 return retStr.str();
01377 }
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388 int ConfigurationView::fillFromJSON(const std::string &json)
01389 {
01390 std::vector<std::string> keys;
01391 keys.push_back ("NAME");
01392 keys.push_back ("COMMENT");
01393 keys.push_back ("AUTHOR");
01394 keys.push_back ("CREATION_TIME");
01395
01396 keys.push_back ("DATA_SET");
01397 enum {
01398 CV_JSON_FILL_NAME,
01399 CV_JSON_FILL_COMMENT,
01400 CV_JSON_FILL_AUTHOR,
01401 CV_JSON_FILL_CREATION_TIME,
01402
01403 CV_JSON_FILL_DATA_SET
01404 };
01405
01406
01407
01408 sourceColumnMismatchCount_ = 0;
01409 sourceColumnMissingCount_ = 0;
01410 sourceColumnNames_.clear();
01411 unsigned int colFoundCount = 0;
01412 unsigned int i = 0;
01413 unsigned int row = -1;
01414 unsigned int colSpeedup = 0;
01415 unsigned int startString, startNumber, endNumber = -1;
01416 unsigned int bracketCount = 0;
01417 unsigned int sqBracketCount = 0;
01418 bool inQuotes = 0;
01419 bool newString = 0;
01420 bool newValue = 0;
01421 bool isDataArray = 0;
01422 bool keyIsMatch, keyIsComment;
01423 unsigned int keyIsMatchIndex, keyIsMatchStorageIndex, keyIsMatchCommentIndex;
01424 const std::string COMMENT_ALT_KEY = "COMMENT";
01425
01426 std::string extractedString = "", currKey = "", currVal = "";
01427 unsigned int currDepth;
01428
01429 std::vector<std::string> jsonPath;
01430 std::vector<char> jsonPathType;
01431 char lastPopType = '_';
01432
01433 unsigned int matchedKey = -1;
01434 unsigned int lastCol = -1;
01435
01436
01437
01438 for(;i<json.size();++i)
01439 {
01440 switch(json[i])
01441 {
01442 case '"':
01443 if(i-1 < json.size() &&
01444 json[i-1] == '\\') break;
01445
01446 inQuotes = !inQuotes;
01447 if(inQuotes)
01448 startString = i;
01449 else
01450 {
01451 extractedString = restoreJSONStringEntities(
01452 json.substr(startString+1,i-startString-1));
01453 newString = 1;
01454 }
01455 break;
01456 case ':':
01457 if(inQuotes) break;
01458
01459
01460 if(jsonPathType[jsonPathType.size()-1] != '{'
01461 || !newString)
01462 {
01463 __MOUT__ << "Invalid ':' position" << std::endl;
01464 return -1;
01465 }
01466
01467
01468 jsonPathType.push_back('K');
01469 jsonPath.push_back(extractedString);
01470 startNumber = i;
01471 newString = 0;
01472 endNumber = -1;
01473 break;
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485 case ',':
01486 if(inQuotes) break;
01487 if(lastPopType == '{')
01488 {
01489
01490 if(jsonPathType[jsonPathType.size()-1] == 'K')
01491 {
01492 lastPopType = 'K';
01493 jsonPath.pop_back();
01494 jsonPathType.pop_back();
01495 }
01496 break;
01497 }
01498
01499 if(newString)
01500 currVal = extractedString;
01501 else
01502 {
01503 if(endNumber == (unsigned int)-1 ||
01504 endNumber <= startNumber)
01505 endNumber = i;
01506
01507 if(endNumber <= startNumber)
01508 currVal = "";
01509 else
01510 currVal = json.substr(startNumber+1,endNumber-startNumber-1);
01511 }
01512
01513 currDepth = bracketCount;
01514
01515 if(jsonPathType[jsonPathType.size()-1] == 'K')
01516 {
01517 currKey = jsonPath[jsonPathType.size()-1];
01518 newValue = 1;
01519
01520
01521 lastPopType = 'K';
01522 jsonPath.pop_back();
01523 jsonPathType.pop_back();
01524 }
01525 else if(jsonPathType[jsonPathType.size()-1] == '[')
01526 {
01527
01528 for(unsigned int k=jsonPathType.size()-2; k<jsonPathType.size(); --k)
01529 if(jsonPathType[k] == 'K')
01530 {
01531 currKey = jsonPath[k];
01532 break;
01533 }
01534 else if(k == 0)
01535 {
01536 __MOUT__ << "Invalid array position" << std::endl;
01537 return -1;
01538 }
01539
01540 newValue = 1;
01541 isDataArray = 1;
01542 }
01543 else
01544 {
01545 __MOUT__ << "Invalid ',' position" << std::endl;
01546 return -1;
01547 }
01548
01549 startNumber = i;
01550 break;
01551
01552 case '{':
01553 if(inQuotes) break;
01554 lastPopType = '_';
01555 jsonPathType.push_back('{');
01556 jsonPath.push_back("{");
01557 ++bracketCount;
01558 break;
01559
01560
01561
01562
01563
01564
01565 case '}':
01566 if(inQuotes) break;
01567
01568 if(lastPopType != '{' &&
01569 jsonPathType[jsonPathType.size()-1] == 'K')
01570 {
01571 currDepth = bracketCount;
01572 currKey = jsonPath[jsonPathType.size()-1];
01573 if(newString)
01574 currVal = extractedString;
01575 else
01576 {
01577 if(endNumber == (unsigned int)-1 ||
01578 endNumber <= startNumber)
01579 endNumber = i;
01580
01581 if(endNumber <= startNumber)
01582 currVal = "";
01583 else
01584 currVal = json.substr(startNumber+1,endNumber-startNumber-1);
01585 }
01586 newValue = 1;
01587
01588 jsonPath.pop_back();
01589 jsonPathType.pop_back();
01590 }
01591
01592 if(jsonPathType[jsonPathType.size()-1] != '{')
01593 {
01594 __MOUT__ << "Invalid '}' position" << std::endl;
01595 return -1;
01596 }
01597 lastPopType = '{';
01598 jsonPath.pop_back();
01599 jsonPathType.pop_back();
01600 --bracketCount;
01601 break;
01602 case '[':
01603 if(inQuotes) break;
01604 jsonPathType.push_back('[');
01605 jsonPath.push_back("[");
01606 ++sqBracketCount;
01607 startNumber = i;
01608 break;
01609 case ']':
01610 if(inQuotes) break;
01611
01612
01613 if(jsonPathType[jsonPathType.size()-1] != '[')
01614 {
01615 __MOUT__ << "Invalid ']' position" << std::endl;
01616 return -1;
01617 }
01618
01619 currDepth = bracketCount;
01620
01621
01622 if(newString)
01623 currVal = extractedString;
01624 else
01625 {
01626 if(endNumber == (unsigned int)-1 ||
01627 endNumber <= startNumber)
01628 endNumber = i;
01629
01630 if(endNumber <= startNumber)
01631 currVal = "";
01632 else
01633 currVal = json.substr(startNumber+1,endNumber-startNumber-1);
01634 }
01635 isDataArray = 1;
01636
01637
01638 for(unsigned int k=jsonPathType.size()-2; k<jsonPathType.size(); --k)
01639 if(jsonPathType[k] == 'K')
01640 {
01641 currKey = jsonPath[k];
01642 break;
01643 }
01644 else if(k == 0)
01645 {
01646 __MOUT__ << "Invalid array position" << std::endl;
01647 return -1;
01648 }
01649
01650
01651 if(jsonPathType[jsonPathType.size()-1] != '[')
01652 {
01653 __MOUT__ << "Invalid ']' position" << std::endl;
01654 return -1;
01655 }
01656 lastPopType = '[';
01657 jsonPath.pop_back();
01658 jsonPathType.pop_back();
01659 --sqBracketCount;
01660 break;
01661 case ' ':
01662 case '\t':
01663 case '\n':
01664 case '\r':
01665 if(inQuotes) break;
01666 if(startNumber != (unsigned int)-1 &&
01667 endNumber == (unsigned int)-1)
01668 endNumber = i;
01669 startNumber = i;
01670 break;
01671 default:;
01672 }
01673
01674 if(0)
01675 {
01676 std::cout << i << ":\t" << json[i] << " - ";
01677
01678 std::cout << "ExtKey=";
01679 for(unsigned int k=0;k<jsonPath.size();++k)
01680 std::cout << jsonPath[k] << "/";
01681 std::cout << " - ";
01682 std::cout << lastPopType << " ";
01683 std::cout << bracketCount << " ";
01684 std::cout << sqBracketCount << " ";
01685 std::cout << inQuotes << " ";
01686 std::cout << newValue << "-";
01687 std::cout << currKey << "-{" << currDepth << "}:" ;
01688 std::cout << currVal << " ";
01689 std::cout << startNumber << "-";
01690 std::cout << endNumber << " ";
01691 std::cout << "\n";
01692 }
01693
01694
01695
01696
01697 if(newValue)
01698 {
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721 matchedKey = -1;
01722 for(unsigned int k=0;k<keys.size();++k)
01723 if((currDepth == 1 && keys[k] == currKey) ||
01724 (currDepth > 1 && keys[k] == jsonPath[1]))
01725 matchedKey = k;
01726
01727 if(matchedKey != (unsigned int)-1)
01728 {
01729
01730
01731
01732 switch(matchedKey)
01733 {
01734 case CV_JSON_FILL_NAME:
01735 if(currDepth == 1) setTableName(currVal);
01736 break;
01737 case CV_JSON_FILL_COMMENT:
01738 if(currDepth == 1) setComment(currVal);
01739 break;
01740 case CV_JSON_FILL_AUTHOR:
01741 if(currDepth == 1) setAuthor(currVal);
01742 break;
01743 case CV_JSON_FILL_CREATION_TIME:
01744 if(currDepth == 1) setCreationTime(strtol(currVal.c_str(),0,10));
01745 break;
01746
01747
01748
01749 case CV_JSON_FILL_DATA_SET:
01750
01751
01752
01753
01754 if(currDepth == 2)
01755 {
01756
01757
01758 unsigned int col, ccnt = 0;
01759 unsigned int noc = getNumberOfColumns();
01760 for(;ccnt<noc;++ccnt)
01761 {
01762
01763
01764
01765
01766 if(fillWithLooseColumnMatching_)
01767 {
01768
01769
01770
01771
01772 col = colSpeedup;
01773
01774
01775 if(col <= lastCol)
01776 row = addRow();
01777 lastCol = col;
01778 if(getNumberOfRows() == 1)
01779 sourceColumnNames_.emplace(currKey);
01780
01781
01782
01783 if(row >= getNumberOfRows())
01784 {
01785 __SS__ << "Invalid row" << std::endl;
01786 std::cout << ss.str();
01787 throw std::runtime_error(ss.str());
01788 return -1;
01789 }
01790
01791 theDataView_[row][col] = currVal;
01792 break;
01793 }
01794 else
01795 {
01796 col = (ccnt + colSpeedup) % noc;
01797
01798
01799
01800
01801 keyIsMatch = true;
01802 keyIsComment = true;
01803 for(keyIsMatchIndex=0, keyIsMatchStorageIndex=0, keyIsMatchCommentIndex=0;
01804 keyIsMatchIndex<currKey.size();++keyIsMatchIndex)
01805 {
01806 if(columnsInfo_[col].getStorageName()[keyIsMatchStorageIndex] == '_')
01807 ++keyIsMatchStorageIndex;
01808 if(currKey[keyIsMatchIndex] == '_')
01809 continue;
01810
01811
01812 if(keyIsMatchStorageIndex >= columnsInfo_[col].getStorageName().size() ||
01813 currKey[keyIsMatchIndex] !=
01814 columnsInfo_[col].getStorageName()[keyIsMatchStorageIndex])
01815 {
01816
01817 keyIsMatch = false;
01818 if(!keyIsComment)
01819 break;
01820 }
01821
01822
01823 if(keyIsComment && keyIsMatchCommentIndex < COMMENT_ALT_KEY.size())
01824 {
01825 if(currKey[keyIsMatchIndex] != COMMENT_ALT_KEY[keyIsMatchCommentIndex])
01826 {
01827
01828 keyIsComment = false;
01829 }
01830 }
01831
01832 ++keyIsMatchStorageIndex;
01833 }
01834
01835 if(keyIsMatch || keyIsComment)
01836 {
01837
01838 if(col <= lastCol)
01839 {
01840 if(getNumberOfRows())
01841 sourceColumnMissingCount_ += getNumberOfColumns() - colFoundCount;
01842
01843 colFoundCount = 0;
01844 row = addRow();
01845 }
01846 lastCol = col;
01847 ++colFoundCount;
01848
01849 if(getNumberOfRows() == 1)
01850 sourceColumnNames_.emplace(currKey);
01851
01852
01853
01854 if(row >= getNumberOfRows())
01855 {
01856 __SS__ << "Invalid row" << std::endl;
01857 __MOUT__ << "\n" << ss.str();
01858 throw std::runtime_error(ss.str());
01859 return -1;
01860 }
01861
01862 theDataView_[row][col] = currVal;
01863 break;
01864 }
01865 }
01866 }
01867
01868 colSpeedup = (colSpeedup + 1) % noc;
01869
01870 if(ccnt >= getNumberOfColumns())
01871 {
01872 __SS__ << "\n\nInvalid column in JSON source data: " <<
01873 currKey << " not found in column names of table named " <<
01874 getTableName() << "." <<
01875 std::endl;
01876 __MOUT__ << "\n" << ss.str();
01877
01878
01879 ++sourceColumnMismatchCount_;
01880 if(getNumberOfRows() == 1)
01881 sourceColumnNames_.emplace(currKey);
01882
01883
01884
01885 }
01886
01887 }
01888 break;
01889 default:;
01890 }
01891
01892 }
01893
01894
01895
01896 newString = 0;
01897 newValue = 0;
01898 isDataArray = 0;
01899 endNumber = -1;
01900 }
01901
01902
01903 }
01904
01905
01906
01907
01908
01909 return 0;
01910 }
01911
01912
01913
01914
01915 bool ConfigurationView::isURIEncodedCommentTheSame(const std::string &comment) const
01916 {
01917 std::string compareStr = decodeURIComponent(comment);
01918 return comment_ == compareStr;
01919 }
01920
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973 int ConfigurationView::fillFromCSV(const std::string &data, const int &dataOffset,
01974 const std::string &author)
01975 throw(std::runtime_error)
01976 {
01977 int r = dataOffset;
01978 int c = 0;
01979
01980 int i = 0;
01981 int j = data.find(',',i);
01982 int k = data.find(';',i);
01983
01984 bool rowWasModified;
01985 unsigned int countRowsModified = 0;
01986 int authorCol = findColByType(ViewColumnInfo::TYPE_AUTHOR);
01987 int timestampCol = findColByType(ViewColumnInfo::TYPE_TIMESTAMP);
01988
01989
01990 while(k != (int)(std::string::npos))
01991 {
01992 rowWasModified = false;
01993 if(r >= (int)getNumberOfRows())
01994 {
01995 addRow();
01996
01997 rowWasModified = true;
01998 }
01999
02000 while(j < k && j != (int)(std::string::npos))
02001 {
02002
02003
02004
02005 if(c >= (int)getNumberOfColumns()-2)
02006 {
02007 i=j+1;
02008 j = data.find(',',i);
02009 ++c;
02010 continue;
02011 }
02012
02013 if(setURIEncodedValue(data.substr(i,j-i),r,c))
02014 rowWasModified = true;
02015
02016 i=j+1;
02017 j = data.find(',',i);
02018 ++c;
02019 }
02020
02021
02022 if(author != "" && rowWasModified)
02023 {
02024 __MOUT__ << "Row=" << r << " was modified!" << std::endl;
02025 setValue(author,r,authorCol);
02026 setValue(time(0),r,timestampCol);
02027 }
02028
02029 if(rowWasModified) ++countRowsModified;
02030
02031 ++r;
02032 c = 0;
02033
02034
02035 i = k+1;
02036 j = data.find(',',i);
02037 k = data.find(';',i);
02038 }
02039
02040
02041 while(r < (int)getNumberOfRows())
02042 {
02043 deleteRow(r);
02044 __MOUT__ << "Row deleted: " << r << std::endl;
02045 ++countRowsModified;
02046 }
02047
02048 __MOUT_INFO__ << "countRowsModified=" <<
02049 countRowsModified << std::endl;
02050
02051 if(!countRowsModified)
02052 {
02053 __SS__ << "No rows were modified! No reason to fill a view with same content." << std::endl;
02054 __MOUT__ << ss.str();
02055 return -1;
02056 }
02057
02058
02059
02060
02061 sourceColumnNames_.clear();
02062 for(unsigned int i=0;i<getNumberOfColumns();++i)
02063 sourceColumnNames_.emplace(getColumnsInfo()[i].getStorageName());
02064
02065 init();
02066
02067
02068
02069
02070
02071
02072 return 0;
02073 }
02074
02075
02076
02077
02078
02079 bool ConfigurationView::setURIEncodedValue(const std::string &value, const unsigned int &r, const unsigned int &c)
02080 {
02081 if(!(c < columnsInfo_.size() && r < getNumberOfRows()))
02082 {
02083 __SS__ << "Invalid row (" << r << ") col (" << c << ") requested!" << std::endl;
02084 throw std::runtime_error(ss.str());
02085 }
02086
02087 std::string valueStr = decodeURIComponent(value);
02088 std::string originalValueStr = getValueAsString(r,c,false);
02089
02090
02091
02092 if(columnsInfo_[c].getDataType() == ViewColumnInfo::DATATYPE_NUMBER)
02093 {
02094
02095 std::string convertedString = convertEnvVariables(valueStr);
02096 if(!isNumber(convertedString))
02097 {
02098 __SS__ << "\tIn configuration " << tableName_
02099 << " at column=" << columnsInfo_[c].getName()
02100 << " the value set (" << convertedString << ")"
02101 << " is not a number! Please fix it or change the column type..." << std::endl;
02102 throw std::runtime_error(ss.str());
02103 }
02104 theDataView_[r][c] = valueStr;
02105 }
02106 else if(columnsInfo_[c].getDataType() == ViewColumnInfo::DATATYPE_TIME)
02107 {
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118 setValue(time_t(strtol(valueStr.c_str(),0,10)),
02119 r,c);
02120 }
02121 else
02122 theDataView_[r][c] = valueStr;
02123
02124
02125 return(originalValueStr != getValueAsString(r,c,false));
02126 }
02127
02128
02129
02130
02131 std::string ConfigurationView::decodeURIComponent(const std::string &data)
02132 {
02133 std::string decodeURIString(data.size(),0);
02134 unsigned int j=0;
02135 for(unsigned int i=0;i<data.size();++i,++j)
02136 {
02137 if(data[i] == '%')
02138 {
02139
02140 if(data[i+1] > '9')
02141 decodeURIString[j] += (data[i+1]-55)*16;
02142 else
02143 decodeURIString[j] += (data[i+1]-48)*16;
02144
02145
02146 if(data[i+2] > '9')
02147 decodeURIString[j] += (data[i+2]-55);
02148 else
02149 decodeURIString[j] += (data[i+2]-48);
02150
02151 i+=2;
02152 }
02153 else
02154 decodeURIString[j] = data[i];
02155 }
02156 decodeURIString.resize(j);
02157 return decodeURIString;
02158 }
02159
02160
02161 void ConfigurationView::resizeDataView(unsigned int nRows, unsigned int nCols)
02162 {
02163
02164 theDataView_.resize(nRows, std::vector<std::string>(nCols));
02165 }
02166
02167
02168
02169
02170
02171 int ConfigurationView::addRow (void)
02172 {
02173 int row = getNumberOfRows();
02174 theDataView_.resize(getNumberOfRows()+1,std::vector<std::string>(getNumberOfColumns()));
02175
02176 std::vector<std::string> defaultRowValues =
02177 getDefaultRowValues();
02178
02179
02180 for(unsigned int col=0;col<getNumberOfColumns();++col)
02181 theDataView_[row][col] = defaultRowValues[col];
02182
02183 return row;
02184 }
02185
02186
02187
02188
02189 void ConfigurationView::deleteRow(int r)
02190 {
02191 if(r >= (int)getNumberOfRows())
02192 {
02193
02194 __SS__ << "Row " << r << " is out of bounds (Row Count = " <<
02195 getNumberOfRows() << ") and can not be deleted." <<
02196 std::endl;
02197 throw std::runtime_error(ss.str());
02198 }
02199
02200 theDataView_.erase(theDataView_.begin()+r);
02201 }
02202
02203
02204
02205
02206
02207
02208
02209
02210
02211
02212
02213
02214
02215
02216
02217 const bool ConfigurationView::getChildLink(const unsigned int &c, bool *isGroup,
02218 std::pair<unsigned int /*link col*/, unsigned int /*link id col*/> *linkPair) const
02219 {
02220
02221
02222
02223
02224 if((*isGroup = columnsInfo_[c].isChildLinkGroupID()) ||
02225 columnsInfo_[c].isChildLinkUID())
02226 {
02227
02228
02229 linkPair->second = c;
02230 std::string index = columnsInfo_[c].getChildLinkIndex();
02231
02232
02233
02234
02235 for(unsigned int col=0; col<columnsInfo_.size(); ++col)
02236 {
02237
02238 if(col == c) continue;
02239 else if(columnsInfo_[col].isChildLink() &&
02240 index == columnsInfo_[col].getChildLinkIndex())
02241 {
02242
02243 __MOUT__ << "getChildLink Found match for col: " << c << " at " << col << std::endl;
02244 linkPair->first = col;
02245 return true;
02246 }
02247 }
02248
02249
02250 __SS__ << "\tIn view: " << tableName_ <<
02251 ", Can't find complete child link for column name " << columnsInfo_[c].getName() << std::endl;
02252 throw std::runtime_error(ss.str());
02253 }
02254
02255 if(!columnsInfo_[c].isChildLink())
02256 return false;
02257
02258
02259 linkPair->first = c;
02260 std::string index = columnsInfo_[c].getChildLinkIndex();
02261
02262
02263
02264
02265 for(unsigned int col=0; col<columnsInfo_.size(); ++col)
02266 {
02267
02268 if(col == c) continue;
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280 if(((columnsInfo_[col].isChildLinkUID() && !(*isGroup = false)) ||
02281 (columnsInfo_[col].isChildLinkGroupID() && (*isGroup = true)))
02282 && index == columnsInfo_[col].getChildLinkIndex())
02283 {
02284
02285
02286 linkPair->second = col;
02287 return true;
02288 }
02289 }
02290
02291
02292 __SS__ << "\tIn view: " << tableName_ <<
02293 ", Can't find complete child link id for column name " << columnsInfo_[c].getName() << std::endl;
02294 throw std::runtime_error(ss.str());
02295 }
02296
02297
02298
02299
02300 bool ConfigurationView::isNumber(const std::string& s) const
02301 {
02302
02303 if(s.find("0x") == 0)
02304 {
02305
02306 for(unsigned int i=2;i<s.size();++i)
02307 {
02308 if(!((s[i] >= '0' && s[i] <= '9') ||
02309 (s[i] >= 'A' && s[i] <= 'F') ||
02310 (s[i] >= 'a' && s[i] <= 'f')
02311 ))
02312 {
02313
02314 return false;
02315 }
02316 }
02317
02318 }
02319 else if(s[0] == 'b')
02320 {
02321
02322
02323 for(unsigned int i=1;i<s.size();++i)
02324 {
02325 if(!((s[i] >= '0' && s[i] <= '1')
02326 ))
02327 {
02328
02329 return false;
02330 }
02331 }
02332 }
02333 else
02334 {
02335
02336 for(unsigned int i=0;i<s.size();++i)
02337 if(!((s[i] >= '0' && s[i] <= '9') ||
02338 s[i] == '.' ||
02339 s[i] == '+' ||
02340 s[i] == '-'))
02341 return false;
02342
02343
02344 }
02345
02346 return true;
02347 }
02348
02349
02350
02351
02352 #ifdef __GNUG__
02353 #include <cstdlib>
02354 #include <memory>
02355 #include <cxxabi.h>
02356
02357 std::string ots_demangle(const char* name) {
02358
02359 int status = -4;
02360
02361
02362 std::unique_ptr<char, void(*)(void*)> res {
02363 abi::__cxa_demangle(name, NULL, NULL, &status),
02364 std::free
02365 };
02366
02367 return (status==0) ? res.get() : name ;
02368 }
02369
02370 #else
02371
02372
02373 std::string ots_demangle(const char* name) {
02374 return name;
02375 }
02376
02377
02378 #endif