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