$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/ConfigurationInterface/ConfigurationTree.h" 00002 00003 #include <typeinfo> 00004 00005 #include "otsdaq-core/ConfigurationInterface/ConfigurationManager.h" 00006 #include "otsdaq-core/Macros/StringMacros.h" 00007 #include "otsdaq-core/TableCore/TableBase.h" 00008 00009 using namespace ots; 00010 00011 #undef __MF_SUBJECT__ 00012 #define __MF_SUBJECT__ "ConfigurationTree" 00013 00014 const std::string ConfigurationTree::DISCONNECTED_VALUE = "X"; 00015 const std::string ConfigurationTree::VALUE_TYPE_DISCONNECTED = "Disconnected"; 00016 const std::string ConfigurationTree::VALUE_TYPE_NODE = "Node"; 00017 00018 //============================================================================== 00019 ConfigurationTree::ConfigurationTree() 00020 : configMgr_(0) 00021 , table_(0) 00022 , groupId_("") 00023 , linkParentConfig_(0) 00024 , linkColName_("") 00025 , linkColValue_("") 00026 , linkBackRow_(0) 00027 , linkBackCol_(0) 00028 , disconnectedTargetName_("") 00029 , disconnectedLinkID_("") 00030 , childLinkIndex_("") 00031 , row_(0) 00032 , col_(0) 00033 , tableView_(0) 00034 { 00035 //__COUT__ << __E__; 00036 //__COUT__ << "EMPTY CONSTRUCTOR ConfigManager: " << configMgr_ << " configuration: " 00037 //<< table_ << __E__; 00038 } //end empty constructor 00039 00040 //============================================================================== 00041 ConfigurationTree::ConfigurationTree(const ConfigurationManager* const& configMgr, 00042 const TableBase* const& config) 00043 : ConfigurationTree(configMgr, 00044 config, 00045 "" /*groupId_*/, 00046 0 /*linkParentConfig_*/, 00047 "" /*linkColName_*/, 00048 "" /*linkColValue_*/, 00049 TableView::INVALID /*linkBackRow_*/, 00050 TableView::INVALID /*linkBackCol_*/, 00051 "" /*disconnectedTargetName_*/, 00052 "" /*disconnectedLinkID_*/, 00053 "" /*childLinkIndex_*/, 00054 TableView::INVALID /*row_*/, 00055 TableView::INVALID /*col_*/) 00056 { 00057 //__COUT__ << __E__; 00058 //__COUT__ << "SHORT CONTRUCTOR ConfigManager: " << configMgr_ << " configuration: " 00059 //<< table_ << __E__; 00060 } //end short constructor 00061 00062 //============================================================================== 00063 ConfigurationTree::ConfigurationTree(const ConfigurationManager* const& configMgr, 00064 const TableBase* const& config, 00065 const std::string& groupId, 00066 const TableBase* const& linkParentConfig, 00067 const std::string& linkColName, 00068 const std::string& linkColValue, 00069 const unsigned int linkBackRow, 00070 const unsigned int linkBackCol, 00071 const std::string& disconnectedTargetName, 00072 const std::string& disconnectedLinkID, 00073 const std::string& childLinkIndex, 00074 const unsigned int row, 00075 const unsigned int col) 00076 : configMgr_(configMgr) 00077 , table_(config) 00078 , groupId_(groupId) 00079 , linkParentConfig_(linkParentConfig) 00080 , linkColName_(linkColName) 00081 , linkColValue_(linkColValue) 00082 , linkBackRow_(linkBackRow) 00083 , linkBackCol_(linkBackCol) 00084 , disconnectedTargetName_(disconnectedTargetName) 00085 , disconnectedLinkID_(disconnectedLinkID) 00086 , childLinkIndex_(childLinkIndex) 00087 , row_(row) 00088 , col_(col) 00089 , tableView_(0) 00090 { 00091 //__COUT__ << __E__; 00092 //__COUT__ << "FULL CONTRUCTOR ConfigManager: " << configMgr_ << " configuration: " << 00093 // table_ << __E__; 00094 if(!configMgr_) // || !table_ || !tableView_) 00095 { 00096 __SS__ << "Invalid empty pointer given to tree!\n" 00097 << "\n\tconfigMgr_=" << configMgr_ << "\n\tconfiguration_=" << table_ 00098 << "\n\tconfigView_=" << tableView_ << __E__; 00099 00100 ss << nodeDump() << __E__; 00101 __SS_THROW__; 00102 } 00103 00104 if(table_) 00105 tableView_ = &(table_->getView()); 00106 00107 // verify UID column exists 00108 if(tableView_ && tableView_->getColumnInfo(tableView_->getColUID()).getType() != 00109 TableViewColumnInfo::TYPE_UID) 00110 { 00111 __SS__ << "Missing UID column (must column of type " 00112 << TableViewColumnInfo::TYPE_UID 00113 << ") in config view : " << tableView_->getTableName() << __E__; 00114 00115 ss << nodeDump() << __E__; 00116 __SS_THROW__; 00117 } 00118 } //end full constructor 00119 00120 //============================================================================== 00121 // destructor 00122 ConfigurationTree::~ConfigurationTree(void) 00123 { 00124 //__COUT__ << __E__; 00125 } //end destructor 00126 00127 //============================================================================== 00128 // print 00129 // print out tree from this node for desired depth 00130 // depth of 0 means print out only this node's value 00131 // depth of 1 means include this node's children's values, etc.. 00132 // depth of -1 means print full tree 00133 void ConfigurationTree::print(const unsigned int& depth, std::ostream& out) const 00134 { 00135 recursivePrint(*this, depth, out, "\t"); 00136 } //end print() 00137 00138 //============================================================================== 00139 void ConfigurationTree::recursivePrint(const ConfigurationTree& t, 00140 unsigned int depth, 00141 std::ostream& out, 00142 std::string space) 00143 { 00144 if(t.isValueNode()) 00145 out << space << t.getValueName() << " :\t" << t.getValueAsString() << __E__; 00146 else 00147 { 00148 if(t.isLinkNode()) 00149 { 00150 out << space << t.getValueName(); 00151 if(t.isDisconnected()) 00152 { 00153 out << " :\t" << t.getValueAsString() << __E__; 00154 return; 00155 } 00156 out << " (" << (t.isGroupLinkNode() ? "Group" : "U") 00157 << "ID=" << t.getValueAsString() << ") : " << __E__; 00158 } 00159 else 00160 out << space << t.getValueAsString() << " : " << __E__; 00161 00162 // if depth>=1 print all children 00163 // child.print(depth-1) 00164 if(depth >= 1) 00165 { 00166 auto C = t.getChildren(); 00167 if(!C.empty()) 00168 out << space << "{" << __E__; 00169 for(auto& c : C) 00170 recursivePrint(c.second, depth - 1, out, space + " "); 00171 if(!C.empty()) 00172 out << space << "}" << __E__; 00173 } 00174 } 00175 } //end recursivePrint() 00176 00177 //============================================================================== 00178 std::string ConfigurationTree::handleValidateValueForColumn( 00179 const TableView* configView, 00180 std::string value, 00181 unsigned int col, 00182 ots::identity<std::string>) const 00183 { 00184 if(!configView) 00185 { 00186 __SS__ << "Null configView" << __E__; 00187 00188 ss << nodeDump() << __E__; 00189 __SS_THROW__; 00190 } 00191 __COUT__ << "handleValidateValueForColumn<string>" << __E__; 00192 return configView->validateValueForColumn(value, col); 00193 } // end std::string handleValidateValueForColumn() 00194 00195 //============================================================================== 00196 // getValue (only std::string value) 00197 // special version of getValue for string type 00198 // Note: necessary because types of std::basic_string<char> cause compiler problems if no 00199 // string specific function 00200 void ConfigurationTree::getValue(std::string& value) const 00201 { 00202 //__COUT__ << row_ << " " << col_ << " p: " << tableView_<< __E__; 00203 00204 if(row_ != TableView::INVALID && 00205 col_ != TableView::INVALID) // this node is a value node 00206 { 00207 // attempt to interpret the value as a tree node path itself 00208 try 00209 { 00210 ConfigurationTree valueAsTreeNode = getValueAsTreeNode(); 00211 // valueAsTreeNode.getValue<T>(value); 00212 __COUT__ << "Success following path to tree node!" << __E__; 00213 // value has been interpreted as a tree node value 00214 // now verify result under the rules of this column 00215 // if(typeid(std::string) == typeid(value)) 00216 00217 // Note: want to interpret table value as though it is in column of different 00218 // table this allows a number to be read as a string, for example, without 00219 // exceptions 00220 value = tableView_->validateValueForColumn(valueAsTreeNode.getValueAsString(), 00221 col_); 00222 00223 __COUT__ << "Successful value!" << __E__; 00224 00225 // else 00226 // value = tableView_->validateValueForColumn<T>( 00227 // valueAsTreeNode.getValueAsString(),col_); 00228 00229 return; 00230 } 00231 catch(...) // tree node path interpretation failed 00232 { 00233 //__COUT__ << "Invalid path, just returning normal value." << __E__; 00234 } 00235 00236 // else normal return 00237 tableView_->getValue(value, row_, col_); 00238 } 00239 else if(row_ == TableView::INVALID && 00240 col_ == TableView::INVALID) // this node is config node maybe with groupId 00241 { 00242 if(isLinkNode() && isDisconnected()) 00243 value = 00244 (groupId_ == "") ? getValueName() : groupId_; // a disconnected link 00245 // still knows its table 00246 // name or groupId 00247 else 00248 value = (groupId_ == "") ? table_->getTableName() : groupId_; 00249 } 00250 else if(row_ == TableView::INVALID) 00251 { 00252 __SS__ << "Malformed ConfigurationTree" << __E__; 00253 __SS_THROW__; 00254 } 00255 else if(col_ == TableView::INVALID) // this node is uid node 00256 tableView_->getValue(value, row_, tableView_->getColUID()); 00257 else 00258 { 00259 __SS__ << "Impossible." << __E__; 00260 __SS_THROW__; 00261 } 00262 } //end getValue() 00263 00264 //============================================================================== 00265 // getValue 00266 // Only std::string value will work. 00267 // If this is a value node, and not type string, configView->getValue should 00268 // throw exception. 00269 // 00270 // NOTE: getValueAsString() method should be preferred if getting the Link UID 00271 // because when disconnected will return "X". getValue() would return the 00272 // column name of the link when disconnected. 00273 // 00275 // Note: if called without template, necessary because types of std::basic_string<char> 00276 // cause compiler problems if no string specific function 00277 std::string ConfigurationTree::getValue() const 00278 { 00279 std::string value; 00280 ConfigurationTree::getValue(value); 00281 return value; 00282 } //end getValue() 00283 00284 //============================================================================== 00285 // getValue (only ConfigurationTree::BitMap value) 00286 // special version of getValue for string type 00287 // Note: necessary because types of std::basic_string<char> cause compiler problems if no 00288 // string specific function 00289 void ConfigurationTree::getValueAsBitMap(ConfigurationTree::BitMap& bitmap) const 00290 { 00291 //__COUT__ << row_ << " " << col_ << " p: " << tableView_<< __E__; 00292 00293 if(row_ != TableView::INVALID && 00294 col_ != TableView::INVALID) // this node is a value node 00295 { 00296 std::string bitmapString; 00297 tableView_->getValue(bitmapString, row_, col_); 00298 00299 __COUTV__(bitmapString); 00300 if(bitmapString == TableViewColumnInfo::DATATYPE_STRING_DEFAULT) 00301 { 00302 bitmap.isDefault_ = true; 00303 return; 00304 } 00305 else 00306 bitmap.isDefault_ = false; 00307 00308 // extract bit map 00309 { 00310 bitmap.bitmap_.clear(); 00311 int row = -1; 00312 bool openRow = false; 00313 unsigned int startInt = -1; 00314 for(unsigned int i = 0; i < bitmapString.length(); i++) 00315 { 00316 __COUTV__(bitmapString[i]); 00317 __COUTV__(row); 00318 __COUTV__(openRow); 00319 __COUTV__(startInt); 00320 __COUTV__(i); 00321 00322 if(!openRow) // need start of row 00323 { 00324 if(bitmapString[i] == '[') 00325 { // open a new row 00326 openRow = true; 00327 ++row; 00328 bitmap.bitmap_.push_back(std::vector<uint64_t>()); 00329 } 00330 else if(bitmapString[i] == ']') 00331 { 00332 break; // ending bracket, done with string 00333 } 00334 else if(bitmapString[i] == ',') // end characters found not within 00335 // row 00336 { 00337 __SS__ 00338 << "Too many ']' or ',' characters in bit map configuration" 00339 << __E__; 00340 00341 ss << nodeDump() << __E__; 00342 __SS_ONLY_THROW__; 00343 } 00344 } 00345 else if(startInt == (unsigned int)-1) // need to find start of number 00346 { 00347 if(bitmapString[i] == ']') // found end of row, instead of start of 00348 // number, assume row ended 00349 { 00350 openRow = false; 00351 } 00352 else if(bitmapString[i] >= '0' && 00353 bitmapString[i] <= '9') // found start of number 00354 { 00355 startInt = i; 00356 } 00357 else if(bitmapString[i] == ',') // comma found without number 00358 { 00359 __SS__ << "Too many ',' characters in bit map configuration" 00360 << __E__; 00361 00362 ss << nodeDump() << __E__; 00363 __SS_ONLY_THROW__; 00364 } 00365 } 00366 else 00367 { 00368 // looking for end of number 00369 00370 if(bitmapString[i] == 00371 ']') // found end of row, assume row and number ended 00372 { 00373 openRow = false; 00374 bitmap.bitmap_[row].push_back(strtoul( 00375 bitmapString.substr(startInt, i - startInt).c_str(), 0, 0)); 00376 startInt = -1; 00377 } 00378 else if(bitmapString[i] == ',') // comma found, assume end of number 00379 { 00380 bitmap.bitmap_[row].push_back(strtoul( 00381 bitmapString.substr(startInt, i - startInt).c_str(), 0, 0)); 00382 startInt = -1; 00383 } 00384 } 00385 } 00386 00387 for(unsigned int r = 0; r < bitmap.bitmap_.size(); ++r) 00388 { 00389 for(unsigned int c = 0; c < bitmap.bitmap_[r].size(); ++c) 00390 { 00391 __COUT__ << r << "," << c << " = " << bitmap.bitmap_[r][c] << __E__; 00392 } 00393 __COUT__ << "================" << __E__; 00394 } 00395 } 00396 } 00397 else 00398 { 00399 __SS__ << "Requesting getValue must be on a value node." << __E__; 00400 00401 ss << nodeDump() << __E__; 00402 __SS_THROW__; 00403 } 00404 } //end getValueAsBitMap() 00405 00406 //============================================================================== 00407 // getValue 00408 // 00409 // special version of getValue for ConfigurationTree::BitMap type 00410 ConfigurationTree::BitMap ConfigurationTree::getValueAsBitMap() const 00411 { 00412 ConfigurationTree::BitMap value; 00413 ConfigurationTree::getValueAsBitMap(value); 00414 return value; 00415 } //end getValueAsBitMap() 00416 00417 //============================================================================== 00418 // getEscapedValue 00419 // Only works if a value node, other exception thrown 00420 std::string ConfigurationTree::getEscapedValue() const 00421 { 00422 if(row_ != TableView::INVALID && 00423 col_ != TableView::INVALID) // this node is a value node 00424 return tableView_->getEscapedValueAsString(row_, col_); 00425 00426 __SS__ << "Can not get escaped value except from a value node!" 00427 << " This node is type '" << getNodeType() << "." << __E__; 00428 00429 ss << nodeDump() << __E__; 00430 __SS_THROW__; 00431 } //end getEscapedValue() 00432 00433 //============================================================================== 00434 // getTableName 00435 const std::string& ConfigurationTree::getTableName(void) const 00436 { 00437 if(!table_) 00438 { 00439 __SS__ << "Can not get configuration name of node with no configuration pointer! " 00440 << "Is there a broken link? " << __E__; 00441 if(linkParentConfig_) 00442 { 00443 ss << "Error occurred traversing from " << linkParentConfig_->getTableName() 00444 << " row " << linkBackRow_ << " col '" 00445 << linkParentConfig_->getView().getColumnInfo(linkBackCol_).getName() 00446 << ".'" << __E__; 00447 } 00448 00449 __SS_ONLY_THROW__; 00450 } 00451 return table_->getTableName(); 00452 } //end getTableName() 00453 00454 //============================================================================== 00455 // getFieldTableName 00456 // returns the configuration name for the node's field. 00457 // Note: for link nodes versus value nodes this has different functionality than 00458 // getTableName() 00459 const std::string& ConfigurationTree::getFieldTableName(void) const 00460 { 00461 // if link node, need config name from parent 00462 if(isLinkNode()) 00463 { 00464 if(!linkParentConfig_) 00465 { 00466 __SS__ << "Can not get configuration name of link node field with no parent " 00467 "configuration pointer!" 00468 << __E__; 00469 ss << nodeDump() << __E__; 00470 __SS_ONLY_THROW__; 00471 } 00472 return linkParentConfig_->getTableName(); 00473 } 00474 else 00475 return getTableName(); 00476 } //end getFieldTableName() 00477 00478 //============================================================================== 00479 // getDisconnectedTableName 00480 const std::string& ConfigurationTree::getDisconnectedTableName(void) const 00481 { 00482 if(isLinkNode() && isDisconnected()) 00483 return disconnectedTargetName_; 00484 00485 __SS__ << "Can not get disconnected target name of node unless it is a disconnected " 00486 "link node!" 00487 << __E__; 00488 00489 ss << nodeDump() << __E__; 00490 __SS_ONLY_THROW__; 00491 } //end getDisconnectedTableName() 00492 00493 //============================================================================== 00494 // getDisconnectedLinkID 00495 const std::string& ConfigurationTree::getDisconnectedLinkID(void) const 00496 { 00497 if(isLinkNode() && isDisconnected()) 00498 return disconnectedLinkID_; 00499 00500 __SS__ << "Can not get disconnected target name of node unless it is a disconnected " 00501 "link node!" 00502 << __E__; 00503 00504 ss << nodeDump() << __E__; 00505 __SS_ONLY_THROW__; 00506 } //end getDisconnectedLinkID() 00507 00508 //============================================================================== 00509 // getTableVersion 00510 const TableVersion& ConfigurationTree::getTableVersion(void) const 00511 { 00512 if(!tableView_) 00513 { 00514 __SS__ << "Can not get configuration version of node with no config view pointer!" 00515 << __E__; 00516 00517 ss << nodeDump() << __E__; 00518 __SS_ONLY_THROW__; 00519 } 00520 return tableView_->getVersion(); 00521 } //end getTableVersion() 00522 00523 //============================================================================== 00524 // getTableCreationTime 00525 const time_t& ConfigurationTree::getTableCreationTime(void) const 00526 { 00527 if(!tableView_) 00528 { 00529 __SS__ << "Can not get configuration creation time of node with no config view " 00530 "pointer!" 00531 << __E__; 00532 00533 ss << nodeDump() << __E__; 00534 __SS_ONLY_THROW__; 00535 } 00536 return tableView_->getCreationTime(); 00537 } //end getTableCreationTime() 00538 00539 //============================================================================== 00540 // getFixedChoices 00541 // returns vector of default + data choices 00542 // Used as choices for tree-view, for example. 00543 std::vector<std::string> ConfigurationTree::getFixedChoices(void) const 00544 { 00545 if(getValueType() != TableViewColumnInfo::TYPE_FIXED_CHOICE_DATA && 00546 getValueType() != TableViewColumnInfo::TYPE_BITMAP_DATA && !isLinkNode()) 00547 { 00548 __SS__ << "Can not get fixed choices of node with value type of '" 00549 << getValueType() << ".' Node must be a link or a value node with type '" 00550 << TableViewColumnInfo::TYPE_BITMAP_DATA << "' or '" 00551 << TableViewColumnInfo::TYPE_FIXED_CHOICE_DATA << ".'" << __E__; 00552 00553 ss << nodeDump() << __E__; 00554 __SS_ONLY_THROW__; 00555 } 00556 00557 std::vector<std::string> retVec; 00558 00559 if(isLinkNode()) 00560 { 00561 if(!linkParentConfig_) 00562 { 00563 __SS__ 00564 << "Can not get fixed choices of node with no parent config view pointer!" 00565 << __E__; 00566 00567 ss << nodeDump() << __E__; 00568 __SS_ONLY_THROW__; 00569 } 00570 00571 //__COUT__ << getChildLinkIndex() << __E__; 00572 //__COUT__ << linkColName_ << __E__; 00573 00574 // for links, col_ = -1, column c needs to change (to ChildLink column of pair) 00575 // get column from parent config pointer 00576 00577 const TableView* parentView = &(linkParentConfig_->getView()); 00578 int c = parentView->findCol(linkColName_); 00579 00580 std::pair<unsigned int /*link col*/, unsigned int /*link id col*/> linkPair; 00581 bool isGroupLink; 00582 parentView->getChildLink(c, isGroupLink, linkPair); 00583 c = linkPair.first; 00584 00585 std::vector<std::string> choices = parentView->getColumnInfo(c).getDataChoices(); 00586 for(const auto& choice : choices) 00587 retVec.push_back(choice); 00588 00589 return retVec; 00590 } 00591 00592 if(!tableView_) 00593 { 00594 __SS__ << "Can not get fixed choices of node with no config view pointer!" 00595 << __E__; 00596 00597 ss << nodeDump() << __E__; 00598 __SS_ONLY_THROW__; 00599 } 00600 00601 // return vector of default + data choices 00602 retVec.push_back(tableView_->getColumnInfo(col_).getDefaultValue()); 00603 std::vector<std::string> choices = tableView_->getColumnInfo(col_).getDataChoices(); 00604 for(const auto& choice : choices) 00605 retVec.push_back(choice); 00606 00607 return retVec; 00608 } //end getFixedChoices() 00609 00610 //============================================================================== 00611 // getValueAsString 00612 // NOTE: getValueAsString() method should be preferred if getting the Link UID 00613 // because when disconnected will return "X". getValue() would return the 00614 // column name of the link when disconnected. 00615 // 00616 // returnLinkTableValue returns the value in the source table as though link was 00617 // not followed to destination table. 00618 const std::string& ConfigurationTree::getValueAsString(bool returnLinkTableValue) const 00619 { 00620 if(isLinkNode()) 00621 { 00622 if(returnLinkTableValue) 00623 return linkColValue_; 00624 else if(isDisconnected()) 00625 return ConfigurationTree::DISCONNECTED_VALUE; 00626 else if(row_ == TableView::INVALID && 00627 col_ == TableView::INVALID) // this link is groupId node 00628 return (groupId_ == "") ? table_->getTableName() : groupId_; 00629 else if(col_ == TableView::INVALID) // this link is uid node 00630 return tableView_->getDataView()[row_][tableView_->getColUID()]; 00631 else 00632 { 00633 __SS__ << "Impossible Link." << __E__; 00634 00635 ss << nodeDump() << __E__; 00636 __SS_THROW__; 00637 } 00638 } 00639 else if(row_ != TableView::INVALID && 00640 col_ != TableView::INVALID) // this node is a value node 00641 return tableView_->getDataView()[row_][col_]; 00642 else if(row_ == TableView::INVALID && 00643 col_ == TableView::INVALID) // this node is config node maybe with groupId 00644 return (groupId_ == "") ? table_->getTableName() : groupId_; 00645 else if(row_ == TableView::INVALID) 00646 { 00647 __SS__ << "Malformed ConfigurationTree" << __E__; 00648 00649 ss << nodeDump() << __E__; 00650 __SS_THROW__; 00651 } 00652 else if(col_ == TableView::INVALID) // this node is uid node 00653 return tableView_->getDataView()[row_][tableView_->getColUID()]; 00654 else 00655 { 00656 __SS__ << "Impossible." << __E__; 00657 00658 ss << nodeDump() << __E__; 00659 __SS_THROW__; 00660 } 00661 } //end getValueAsString() 00662 00663 //============================================================================== 00664 // getUIDAsString 00665 // returns UID associated with current value node or UID-Link node 00666 // 00667 const std::string& ConfigurationTree::getUIDAsString(void) const 00668 { 00669 if(isValueNode() || isUIDLinkNode()) 00670 return tableView_->getDataView()[row_][tableView_->getColUID()]; 00671 00672 { 00673 __SS__ << "Can not get UID of node with type '" << getNodeType() 00674 << ".' Node type must be '" << ConfigurationTree::NODE_TYPE_VALUE 00675 << "' or '" << ConfigurationTree::NODE_TYPE_UID_LINK << ".'" << __E__; 00676 00677 ss << nodeDump() << __E__; 00678 __SS_ONLY_THROW__; 00679 } 00680 } //end getUIDAsString() 00681 00682 //============================================================================== 00683 // getValueDataType 00684 // e.g. used to determine if node is type NUMBER 00685 const std::string& ConfigurationTree::getValueDataType(void) const 00686 { 00687 if(isValueNode()) 00688 return tableView_->getColumnInfo(col_).getDataType(); 00689 else // must be std::string 00690 return TableViewColumnInfo::DATATYPE_STRING; 00691 } //end getValueDataType() 00692 00693 //============================================================================== 00694 // isDefaultValue 00695 // returns true if is a value node and value is the default for the type 00696 bool ConfigurationTree::isDefaultValue(void) const 00697 { 00698 if(!isValueNode()) 00699 return false; 00700 00701 if(getValueDataType() == TableViewColumnInfo::DATATYPE_STRING) 00702 { 00703 if(getValueType() == TableViewColumnInfo::TYPE_ON_OFF || 00704 getValueType() == TableViewColumnInfo::TYPE_TRUE_FALSE || 00705 getValueType() == TableViewColumnInfo::TYPE_YES_NO) 00706 return getValueAsString() == 00707 TableViewColumnInfo::DATATYPE_BOOL_DEFAULT; // default to OFF, NO, 00708 // FALSE 00709 else if(getValueType() == TableViewColumnInfo::TYPE_COMMENT) 00710 return getValueAsString() == TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT || 00711 getValueAsString() == 00712 ""; // in case people delete default comment, allow blank also 00713 else 00714 return getValueAsString() == TableViewColumnInfo::DATATYPE_STRING_DEFAULT; 00715 } 00716 else if(getValueDataType() == TableViewColumnInfo::DATATYPE_NUMBER) 00717 return getValueAsString() == TableViewColumnInfo::DATATYPE_NUMBER_DEFAULT; 00718 else if(getValueDataType() == TableViewColumnInfo::DATATYPE_TIME) 00719 return getValueAsString() == TableViewColumnInfo::DATATYPE_TIME_DEFAULT; 00720 else 00721 return false; 00722 } //end isDefaultValue() 00723 00724 //============================================================================== 00725 // getValueType 00726 // e.g. used to determine if node is type TYPE_DATA, TYPE_ON_OFF, etc. 00727 const std::string& ConfigurationTree::getValueType(void) const 00728 { 00729 if(isValueNode()) 00730 return tableView_->getColumnInfo(col_).getType(); 00731 else if(isLinkNode() && isDisconnected()) 00732 return ConfigurationTree::VALUE_TYPE_DISCONNECTED; 00733 else // just call all non-value nodes data 00734 return ConfigurationTree::VALUE_TYPE_NODE; 00735 } //end getValueType() 00736 00737 //============================================================================== 00738 // getColumnInfo 00739 // only sensible for value node 00740 const TableViewColumnInfo& ConfigurationTree::getColumnInfo(void) const 00741 { 00742 if(isValueNode()) 00743 return tableView_->getColumnInfo(col_); 00744 else 00745 { 00746 __SS__ << "Can only get column info from a value node! " 00747 << "The node type is " << getNodeType() << __E__; 00748 00749 ss << nodeDump() << __E__; 00750 __SS_THROW__; 00751 } 00752 } //end getColumnInfo() 00753 00754 //============================================================================== 00755 // getRow 00756 const unsigned int& ConfigurationTree::getRow(void) const { return row_; } 00757 00758 //============================================================================== 00759 // getColumn 00760 const unsigned int& ConfigurationTree::getColumn(void) const { return col_; } 00761 00762 //============================================================================== 00763 // getFieldRow 00764 // return field's row (different handling for value vs. link node) 00765 const unsigned int& ConfigurationTree::getFieldRow(void) const 00766 { 00767 if(isLinkNode()) 00768 { 00769 // for links, need to use parent info to determine 00770 return linkBackRow_; 00771 } 00772 else 00773 return row_; 00774 } //end getFieldRow() 00775 00776 //============================================================================== 00777 // getFieldColumn 00778 // return field's column (different handling for value vs. link node) 00779 const unsigned int& ConfigurationTree::getFieldColumn(void) const 00780 { 00781 if(isLinkNode()) 00782 { 00783 // for links, need to use parent info to determine 00784 return linkBackCol_; 00785 } 00786 else 00787 return col_; 00788 } //end getFieldColumn() 00789 00790 //============================================================================== 00791 // getChildLinkIndex 00792 const std::string& ConfigurationTree::getChildLinkIndex(void) const 00793 { 00794 if(!isLinkNode()) 00795 { 00796 __SS__ << "Can only get link ID from a link! " 00797 << "The node type is " << getNodeType() << __E__; 00798 00799 ss << nodeDump() << __E__; 00800 __SS_THROW__; 00801 } 00802 return childLinkIndex_; 00803 } //end getChildLinkIndex() 00804 00805 //============================================================================== 00806 // getValueName 00807 // e.g. used to determine column name of value node 00808 const std::string& ConfigurationTree::getValueName(void) const 00809 { 00810 if(isValueNode()) 00811 return tableView_->getColumnInfo(col_).getName(); 00812 else if(isLinkNode()) 00813 return linkColName_; 00814 else 00815 { 00816 __SS__ << "Can only get value name of a value node!" << __E__; 00817 00818 ss << nodeDump() << __E__; 00819 __SS_THROW__; 00820 } 00821 } //end getValueName() 00822 00823 //============================================================================== 00824 // recurse 00825 // Used by ConfigurationTree to handle / syntax of getNode 00826 ConfigurationTree ConfigurationTree::recurse(const ConfigurationTree& tree, 00827 const std::string& childPath, 00828 bool doNotThrowOnBrokenUIDLinks, 00829 const std::string& originalNodeString) 00830 { 00831 //__COUT__ << tree.row_ << " " << tree.col_ << __E__; 00832 //__COUT__ << "childPath=" << childPath << " " << childPath.length() << __E__; 00833 if(childPath.length() <= 1) // only "/" or "" 00834 return tree; 00835 return tree.recursiveGetNode( 00836 childPath, doNotThrowOnBrokenUIDLinks, originalNodeString); 00837 } //end recurse() 00838 00849 // std::string ConfigurationTree::getRecordFieldValueAsString(std::string fieldName) const 00850 //{ 00851 // //enforce that starting point is a table node 00852 // if(!isUIDNode()) 00853 // { 00854 // __SS__ << "Can only get getRecordFieldValueAsString from a uid node! " << 00855 // "The node type is " << getNodeType() << __E__; 00856 // __COUT__ << "\n" << ss.str() << __E__; 00857 // __SS_THROW__; 00858 // } 00859 // 00860 // unsigned int c = tableView_->findCol(fieldName); 00861 // return tableView_->getDataView()[row_][c]; 00862 //} 00863 00864 //============================================================================== 00865 // getNode 00866 // Connected to recursiveGetNode() 00867 // 00868 // nodeString can be a multi-part path using / delimiter 00869 // use: 00870 // getNode(/uid/col) or getNode(uid)->getNode(col) 00871 // 00872 // if doNotThrowOnBrokenUIDLinks 00873 // then catch exceptions on UID links and call disconnected 00874 ConfigurationTree ConfigurationTree::getNode(const std::string& nodeString, 00875 bool doNotThrowOnBrokenUIDLinks) const 00876 { 00877 return recursiveGetNode( 00878 nodeString, doNotThrowOnBrokenUIDLinks, "" /*originalNodeString*/); 00879 } //end getNode() connected to recursiveGetNode() 00880 ConfigurationTree ConfigurationTree::recursiveGetNode( 00881 const std::string& nodeString, 00882 bool doNotThrowOnBrokenUIDLinks, 00883 const std::string& originalNodeString) const 00884 { 00885 //__COUT__ << "nodeString=" << nodeString << " " << nodeString.length() << __E__; 00886 //__COUT__ << "doNotThrowOnBrokenUIDLinks=" << doNotThrowOnBrokenUIDLinks << 00887 // __E__; 00888 00889 // get nodeName (in case of / syntax) 00890 if(nodeString.length() < 1) 00891 { 00892 __SS__ << "Invalid empty node name! Looking for child node from node '" 00893 << getValue() << "'..." << __E__; 00894 00895 ss << nodeDump() << __E__; 00896 __SS_THROW__; 00897 } 00898 00899 bool startingSlash = nodeString[0] == '/'; 00900 00901 std::string nodeName = nodeString.substr( 00902 startingSlash ? 1 : 0, nodeString.find('/', 1) - (startingSlash ? 1 : 0)); 00903 //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << __E__; 00904 00905 std::string childPath = 00906 nodeString.substr(nodeName.length() + (startingSlash ? 1 : 0)); 00907 //__COUT__ << "childPath=" << childPath << " " << childPath.length() << __E__; 00908 00909 // if this tree is beginning at a configuration.. then go to uid, and vice versa 00910 00911 try 00912 { 00913 //__COUT__ << row_ << " " << col_ << " " << groupId_ << " " << tableView_ << 00914 // __E__; 00915 if(!table_) 00916 { 00917 // root node 00918 // so return config node 00919 return recurse(configMgr_->getNode(nodeName), 00920 childPath, 00921 doNotThrowOnBrokenUIDLinks, 00922 originalNodeString); 00923 } 00924 else if(row_ == TableView::INVALID && col_ == TableView::INVALID) 00925 { 00926 // config node 00927 00928 if(!tableView_) 00929 { 00930 __SS__ << "Missing configView pointer! Likely attempting to access a " 00931 "child node through a disconnected link node." 00932 << __E__; 00933 00934 ss << nodeDump() << __E__; 00935 __SS_THROW__; 00936 } 00937 00938 // this node is config node, so return uid node considering groupid 00939 return recurse( 00940 ConfigurationTree( 00941 configMgr_, 00942 table_, 00943 "", // no new groupId string, not a link 00944 0 /*linkParentConfig_*/, 00945 "", // link node name, not a link 00946 "", // link node value, not a link 00947 TableView::INVALID /*linkBackRow_*/, 00948 TableView::INVALID /*linkBackCol_*/, 00949 "", // ignored disconnected target name, not a link 00950 "", // ignored disconnected link id, not a link 00951 "", 00952 // if this node is group config node, consider that when getting rows 00953 (groupId_ == "") 00954 ? tableView_->findRow(tableView_->getColUID(), nodeName) 00955 : tableView_->findRowInGroup(tableView_->getColUID(), 00956 nodeName, 00957 groupId_, 00958 childLinkIndex_)), 00959 childPath, 00960 doNotThrowOnBrokenUIDLinks, 00961 originalNodeString); 00962 } 00963 else if(row_ == TableView::INVALID) 00964 { 00965 __SS__ << "Malformed ConfigurationTree" << __E__; 00966 00967 ss << nodeDump() << __E__; 00968 __SS_THROW__; 00969 } 00970 else if(col_ == TableView::INVALID) 00971 { 00972 // this node is uid node, so return link, group link, disconnected, or value 00973 // node 00974 00975 //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << 00976 // __E__; 00977 00978 // if the value is a unique link .. 00979 // return a uid node! 00980 // if the value is a group link 00981 // return a config node with group string 00982 // else.. return value node 00983 00984 if(!tableView_) 00985 { 00986 __SS__ << "Missing configView pointer! Likely attempting to access a " 00987 "child node through a disconnected link node." 00988 << __E__; 00989 00990 ss << nodeDump() << __E__; 00991 __SS_THROW__; 00992 } 00993 00994 unsigned int c = tableView_->findCol(nodeName); 00995 std::pair<unsigned int /*link col*/, unsigned int /*link id col*/> linkPair; 00996 bool isGroupLink, isLink; 00997 if((isLink = tableView_->getChildLink(c, isGroupLink, linkPair)) && 00998 !isGroupLink) 00999 { 01000 //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << 01001 // __E__; is a unique link, return uid node in new configuration 01002 // need new configuration pointer 01003 // and row of linkUID in new configuration 01004 01005 const TableBase* childConfig; 01006 try 01007 { 01008 childConfig = configMgr_->getTableByName( 01009 tableView_->getDataView()[row_][linkPair.first]); 01010 childConfig->getView(); // get view as a test for an active view 01011 01012 if(doNotThrowOnBrokenUIDLinks) // try a test of getting row 01013 { 01014 childConfig->getView().findRow( 01015 childConfig->getView().getColUID(), 01016 tableView_->getDataView()[row_][linkPair.second]); 01017 } 01018 } 01019 catch(...) 01020 { 01021 // __COUT_WARN__ << "Found disconnected node! (" << 01022 // nodeName 01023 //<< 01024 // ":" << 01025 // tableView_->getDataView()[row_][linkPair.first] 01026 //<< ")" << " at entry with UID " << 01027 // tableView_->getDataView()[row_][tableView_->getColUID()] 01028 //<< __E__; do not recurse further 01029 return ConfigurationTree( 01030 configMgr_, 01031 0, 01032 "", 01033 table_, // linkParentConfig_ 01034 nodeName, 01035 tableView_->getDataView()[row_][c], // this the link node field 01036 // associated value (matches 01037 // targeted column) 01038 row_ /*linkBackRow_*/, 01039 c /*linkBackCol_*/, 01040 tableView_->getDataView()[row_][linkPair.first], // give 01041 // disconnected 01042 // target name 01043 tableView_->getDataView()[row_][linkPair.second], // give 01044 // disconnected 01045 // link ID 01046 tableView_->getColumnInfo(c).getChildLinkIndex()); 01047 } 01048 01049 return recurse( 01050 ConfigurationTree( // this is a link node 01051 configMgr_, 01052 childConfig, 01053 "", // no new groupId string 01054 table_, // linkParentConfig_ 01055 nodeName, // this is a link node 01056 tableView_->getDataView()[row_][c], // this the link node field 01057 // associated value (matches 01058 // targeted column) 01059 row_ /*linkBackRow_*/, 01060 c /*linkBackCol_*/, 01061 "", // ignore since is connected 01062 "", // ignore since is connected 01063 tableView_->getColumnInfo(c).getChildLinkIndex(), 01064 childConfig->getView().findRow( 01065 childConfig->getView().getColUID(), 01066 tableView_->getDataView()[row_][linkPair.second])), 01067 childPath, 01068 doNotThrowOnBrokenUIDLinks, 01069 originalNodeString); 01070 } 01071 else if(isLink) 01072 { 01073 //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << 01074 // __E__; is a group link, return new configuration with group string 01075 // need new configuration pointer 01076 // and group string 01077 01078 const TableBase* childConfig; 01079 try 01080 { 01081 childConfig = configMgr_->getTableByName( 01082 tableView_->getDataView()[row_][linkPair.first]); 01083 childConfig->getView(); // get view as a test for an active view 01084 } 01085 catch(...) 01086 { 01087 if(tableView_->getDataView()[row_][linkPair.first] != 01088 TableViewColumnInfo::DATATYPE_LINK_DEFAULT) 01089 __COUT_WARN__ 01090 << "Found disconnected node! Failed link target " 01091 "from nodeName=" 01092 << nodeName << " to table:id=" 01093 << tableView_->getDataView()[row_][linkPair.first] << ":" 01094 << tableView_->getDataView()[row_][linkPair.second] << __E__; 01095 01096 // do not recurse further 01097 return ConfigurationTree( 01098 configMgr_, 01099 0, 01100 tableView_->getDataView()[row_][linkPair.second], // groupID 01101 table_, // linkParentConfig_ 01102 nodeName, 01103 tableView_->getDataView()[row_][c], // this the link node field 01104 // associated value (matches 01105 // targeted column) 01106 row_ /*linkBackRow_*/, 01107 c /*linkBackCol_*/, 01108 tableView_->getDataView()[row_][linkPair.first], // give 01109 // disconnected 01110 // target name 01111 tableView_->getDataView()[row_][linkPair.second], // give 01112 // disconnected 01113 // target name 01114 tableView_->getColumnInfo(c).getChildLinkIndex()); 01115 } 01116 01117 return recurse( 01118 ConfigurationTree( // this is a link node 01119 configMgr_, 01120 childConfig, 01121 tableView_ 01122 ->getDataView()[row_][linkPair.second], // groupId string 01123 table_, // linkParentConfig_ 01124 nodeName, // this is a link node 01125 tableView_->getDataView()[row_][c], // this the link node field 01126 // associated value (matches 01127 // targeted column) 01128 row_ /*linkBackRow_*/, 01129 c /*linkBackCol_*/, 01130 "", // ignore since is connected 01131 "", // ignore since is connected 01132 tableView_->getColumnInfo(c).getChildLinkIndex()), 01133 childPath, 01134 doNotThrowOnBrokenUIDLinks, 01135 originalNodeString); 01136 } 01137 else 01138 { 01139 //__COUT__ << "nodeName=" << nodeName << " " << nodeName.length() << 01140 // __E__; return value node 01141 return ConfigurationTree(configMgr_, 01142 table_, 01143 "", 01144 0 /*linkParentConfig_*/, 01145 "", 01146 "", 01147 TableView::INVALID /*linkBackRow_*/, 01148 TableView::INVALID /*linkBackCol_*/, 01149 "", 01150 "" /*disconnectedLinkID*/, 01151 "", 01152 row_, 01153 c); 01154 } 01155 } 01156 } 01157 catch(std::runtime_error& e) 01158 { 01159 __SS__ << "\n\nError occurred descending from node '" << getValue() 01160 << "' in table '" << getTableName() << "' looking for child '" << nodeName 01161 << "'\n\n" 01162 << __E__; 01163 ss << "The original node search string was '" << originalNodeString << ".'" 01164 << __E__; 01165 ss << "--- Additional error detail: \n\n" << e.what() << __E__; 01166 01167 ss << nodeDump() << __E__; 01168 __SS_ONLY_THROW__; 01169 } 01170 catch(...) 01171 { 01172 __SS__ << "\n\nError occurred descending from node '" << getValue() 01173 << "' in table '" << getTableName() << "' looking for child '" << nodeName 01174 << "'\n\n" 01175 << __E__; 01176 ss << "The original node search string was '" << originalNodeString << ".'" 01177 << __E__; 01178 01179 ss << nodeDump() << __E__; 01180 __SS_ONLY_THROW__; 01181 } 01182 01183 // this node is value node, so has no node to choose from 01184 __SS__ 01185 << "\n\nError occurred descending from node '" << getValue() << "' in table '" 01186 << getTableName() << "' looking for child '" << nodeName << "'\n\n" 01187 << "Invalid depth! getNode() called from a value point in the Configuration Tree." 01188 << __E__; 01189 ss << "The original node search string was '" << originalNodeString << ".'" << __E__; 01190 01191 ss << nodeDump() << __E__; 01192 __SS_ONLY_THROW__; // this node is value node, cant go any deeper! 01193 } //end recursiveGetNode() 01194 01195 //============================================================================== 01196 // nodeDump 01197 // Useful for debugging a node failure, like when throwing an exception 01198 std::string ConfigurationTree::nodeDump(void) const 01199 { 01200 __SS__ << "ConfigurationTree::nodeDump() " 01201 "=====================================\nConfigurationTree::nodeDump():" 01202 << __E__; 01203 01204 // try each level of debug.. and ignore errors 01205 try 01206 { 01207 ss << "\t" 01208 << "Error occurred from node '" << getValueAsString() << "'..." << __E__; 01209 } 01210 catch(...) 01211 { 01212 } // ignore errors 01213 try 01214 { 01215 ss << "\t" 01216 << "Error occurred from node '" << getValue() << "' in table '" 01217 << getTableName() << ".'" << __E__; 01218 } 01219 catch(...) 01220 { 01221 } // ignore errors 01222 try 01223 { 01224 auto children = getChildrenNames(); 01225 ss << "\t" 01226 << "Here is the list of possible children (count = " << children.size() 01227 << "):" << __E__; 01228 for(auto& child : children) 01229 ss << "\t\t" << child << __E__; 01230 if(tableView_) 01231 { 01232 ss << "\n\nHere is the culprit table printout:\n\n"; 01233 tableView_->print(ss); 01234 } 01235 } 01236 catch(...) 01237 { 01238 } // ignore errors trying to show children 01239 01240 try 01241 { 01242 ss << "\n\n" << StringMacros::stackTrace() << __E__; 01243 } 01244 catch(...) 01245 { 01246 } // ignore errors 01247 01248 ss << "end ConfigurationTree::nodeDump() =====================================" 01249 << __E__; 01250 01251 return ss.str(); 01252 } //end nodeDump() 01253 01254 //============================================================================== 01255 ConfigurationTree ConfigurationTree::getBackNode(std::string nodeName, 01256 unsigned int backSteps) const 01257 { 01258 for(unsigned int i = 0; i < backSteps; i++) 01259 nodeName = nodeName.substr(0, nodeName.find_last_of('/')); 01260 01261 return getNode(nodeName); 01262 } //end getBackNode() 01263 01264 //============================================================================== 01265 ConfigurationTree ConfigurationTree::getForwardNode(std::string nodeName, 01266 unsigned int forwardSteps) const 01267 { 01268 unsigned int s = 0; 01269 01270 // skip all leading /'s 01271 while(s < nodeName.length() && nodeName[s] == '/') 01272 ++s; 01273 01274 for(unsigned int i = 0; i < forwardSteps; i++) 01275 s = nodeName.find('/', s) + 1; 01276 01277 return getNode(nodeName.substr(0, s)); 01278 } //end getForwardNode() 01279 01280 //============================================================================== 01281 // isValueNode 01282 // if true, then this is a leaf node, i.e. there can be no children, only a value 01283 bool ConfigurationTree::isValueNode(void) const 01284 { 01285 return (row_ != TableView::INVALID && col_ != TableView::INVALID); 01286 } //end isValueNode() 01287 01288 //============================================================================== 01289 // isValueBoolType 01290 // if true, then this is a leaf node with BOOL type 01291 bool ConfigurationTree::isValueBoolType(void) const 01292 { 01293 return isValueNode() && tableView_->getColumnInfo(col_).isBoolType(); 01294 } // end isValueBoolType() 01295 01296 //============================================================================== 01297 // isValueNumberDataType 01298 // if true, then this is a leaf node with NUMBER data type 01299 bool ConfigurationTree::isValueNumberDataType(void) const 01300 { 01301 return isValueNode() && tableView_->getColumnInfo(col_).isNumberDataType(); 01302 } // end isValueBoolType() 01303 01304 //============================================================================== 01305 // isDisconnected 01306 // if true, then this is a disconnected node, i.e. there is a configuration link missing 01307 // (this is possible when the configuration is loaded in stages and the complete tree 01308 // may not be available, yet) 01309 bool ConfigurationTree::isDisconnected(void) const 01310 { 01311 if(!isLinkNode()) 01312 { 01313 __SS__ << "\n\nError occurred testing link connection at node with value '" 01314 << getValue() << "' in table '" << getTableName() << "'\n\n" 01315 << __E__; 01316 ss << "This is not a Link node! It is node type '" << getNodeType() 01317 << ".' Only a Link node can be disconnected." << __E__; 01318 01319 ss << nodeDump() << __E__; 01320 __SS_ONLY_THROW__; 01321 } 01322 01323 return !table_ || !tableView_; 01324 } //end isDisconnected() 01325 01326 //============================================================================== 01327 // isLinkNode 01328 // if true, then this is a link node 01329 bool ConfigurationTree::isLinkNode(void) const { return linkColName_ != ""; } 01330 01331 //============================================================================== 01332 // getNodeType 01333 // return node type as string 01334 const std::string ConfigurationTree::NODE_TYPE_GROUP_TABLE = "GroupTableNode"; 01335 const std::string ConfigurationTree::NODE_TYPE_TABLE = "TableNode"; 01336 const std::string ConfigurationTree::NODE_TYPE_GROUP_LINK = "GroupLinkNode"; 01337 const std::string ConfigurationTree::NODE_TYPE_UID_LINK = "UIDLinkNode"; 01338 const std::string ConfigurationTree::NODE_TYPE_VALUE = "ValueNode"; 01339 const std::string ConfigurationTree::NODE_TYPE_UID = "UIDNode"; 01340 const std::string ConfigurationTree::NODE_TYPE_ROOT = "RootNode"; 01341 01342 std::string ConfigurationTree::getNodeType(void) const 01343 { 01344 if(!table_) 01345 return ConfigurationTree::NODE_TYPE_ROOT; 01346 if(isConfigurationNode() && groupId_ != "") 01347 return ConfigurationTree::NODE_TYPE_GROUP_TABLE; 01348 if(isConfigurationNode()) 01349 return ConfigurationTree::NODE_TYPE_TABLE; 01350 if(isGroupLinkNode()) 01351 return ConfigurationTree::NODE_TYPE_GROUP_LINK; 01352 if(isLinkNode()) 01353 return ConfigurationTree::NODE_TYPE_UID_LINK; 01354 if(isValueNode()) 01355 return ConfigurationTree::NODE_TYPE_VALUE; 01356 return ConfigurationTree::NODE_TYPE_UID; 01357 } //end getNodeType() 01358 01359 //============================================================================== 01360 // isGroupLinkNode 01361 // if true, then this is a group link node 01362 bool ConfigurationTree::isGroupLinkNode(void) const 01363 { 01364 return (isLinkNode() && groupId_ != ""); 01365 } 01366 01367 //============================================================================== 01368 // isUIDLinkNode 01369 // if true, then this is a uid link node 01370 bool ConfigurationTree::isUIDLinkNode(void) const 01371 { 01372 return (isLinkNode() && groupId_ == ""); 01373 } 01374 01375 //============================================================================== 01376 // isUIDNode 01377 // if true, then this is a uid node 01378 bool ConfigurationTree::isUIDNode(void) const 01379 { 01380 return (row_ != TableView::INVALID && col_ == TableView::INVALID); 01381 } 01382 01383 //============================================================================== 01384 // getCommonFields 01385 // wrapper for ...recursiveGetCommonFields 01386 // 01387 // returns common fields in order encountered 01388 // including through UID links depending on depth specified 01389 // 01390 // Field := {Table, UID, Column Name, Relative Path, TableViewColumnInfo} 01391 // 01392 // if fieldAcceptList or fieldRejectList are not empty, 01393 // then reject any that are not in field accept filter list 01394 // and reject any that are in field reject filter list 01395 // 01396 // will only go to specified depth looking for fields 01397 // (careful to prevent infinite loops in tree navigation) 01398 // 01399 std::vector<ConfigurationTree::RecordField> ConfigurationTree::getCommonFields( 01400 const std::vector<std::string /*uid*/>& recordList, 01401 const std::vector<std::string /*relative-path*/>& fieldAcceptList, 01402 const std::vector<std::string /*relative-path*/>& fieldRejectList, 01403 unsigned int depth) const 01404 { 01405 // enforce that starting point is a table node 01406 if(!isRootNode() && !isConfigurationNode()) 01407 { 01408 __SS__ << "Can only get getCommonFields from a root or table node! " 01409 << "The node type is " << getNodeType() << __E__; 01410 01411 ss << nodeDump() << __E__; 01412 __SS_THROW__; 01413 } 01414 01415 std::vector<ConfigurationTree::RecordField> fieldCandidateList; 01416 std::vector<int> fieldCount; //-1 := guaranteed, else count must match num of records 01417 01418 --depth; // decrement for recursion 01419 01420 // for each record in <record list> 01421 // loop through all record's children 01422 // if isValueNode (value nodes are possible field candidates!) 01423 // if first uid record 01424 // add field to <field candidates list> if in <field filter list> 01425 // mark <field count> as guaranteed -1 (all these fields must be common 01426 // for UIDs in same table) 01427 // else not first uid record, do not need to check, must be same as first 01428 // record! else if depth > 0 and UID-Link Node recursively (call 01429 // recursiveGetCommonFields()) 01430 // ===================== 01431 // Start recursiveGetCommonFields() 01432 // --depth; 01433 // loop through all children 01434 // if isValueNode (value nodes are possible field candidates!) 01435 // if first uid record 01436 // add field to <field candidates list> if in <field 01437 // filter list> initial mark <field count> as 1 01438 // else 01439 // if field is in <field candidates list>, 01440 // increment <field count> for field candidate 01441 // else if field is not in list, ignore field 01442 // else if depth > 0 and is UID-Link 01443 // if Link Table/UID pair is not found in <field candidates 01444 // list> (avoid endless loops through tree) 01445 // recursiveGetCommonFields() 01446 // ===================== 01447 // 01448 // 01449 // loop through all field candidates 01450 // remove those with <field count> != num of records 01451 // 01452 // 01453 // return result 01454 01455 bool found; // used in loops 01456 // auto tableName = isRootNode()?"/":getTableName(); //all records will share this 01457 // table name 01458 01459 for(unsigned int i = 0; i < recordList.size(); ++i) 01460 { 01461 //__COUT__ << "Checking " << recordList[i] << __E__; 01462 01463 auto recordChildren = getNode(recordList[i]).getChildren(); 01464 for(const auto& fieldNode : recordChildren) 01465 { 01466 // __COUT__ << "All... " << fieldNode.second.getNodeType() << 01467 // " -- " << fieldNode.first << __E__; 01468 if(fieldNode.second.isValueNode()) 01469 { 01470 // skip author and record insertion time 01471 if(fieldNode.second.getColumnInfo().getType() == 01472 TableViewColumnInfo::TYPE_AUTHOR || 01473 fieldNode.second.getColumnInfo().getType() == 01474 TableViewColumnInfo::TYPE_TIMESTAMP) 01475 continue; 01476 01477 //__COUT__ << "isValueNode " << fieldNode.first << __E__; 01478 if(!i) // first uid record 01479 { 01480 // check field accept filter list 01481 found = fieldAcceptList.size() ? false 01482 : true; // accept if no filter list 01483 for(const auto& fieldFilter : fieldAcceptList) 01484 if(StringMacros::wildCardMatch(fieldFilter, fieldNode.first)) 01485 { 01486 found = true; 01487 break; 01488 } 01489 01490 if(found) 01491 { 01492 // check field reject filter list 01493 01494 found = true; // accept if no filter list 01495 for(const auto& fieldFilter : fieldRejectList) 01496 if(StringMacros::wildCardMatch(fieldFilter, fieldNode.first)) 01497 { 01498 found = false; // reject if match 01499 break; 01500 } 01501 } 01502 01503 // if found, guaranteed field (all these fields must be common for 01504 // UIDs in same table) 01505 if(found) 01506 { 01507 fieldCandidateList.push_back(ConfigurationTree::RecordField( 01508 fieldNode.second.getTableName(), 01509 recordList[i], 01510 fieldNode.first, 01511 "", // relative path, not including columnName_ 01512 &fieldNode.second.getColumnInfo())); 01513 fieldCount.push_back(-1); // mark guaranteed field 01514 } 01515 } 01516 // else // not first uid record, do not need to check, must be same as 01517 // first record! 01518 } 01519 else if(depth > 0 && fieldNode.second.isUIDLinkNode() && 01520 !fieldNode.second.isDisconnected()) 01521 { 01522 //__COUT__ << "isUIDLinkNode " << fieldNode.first << __E__; 01523 fieldNode.second.recursiveGetCommonFields( 01524 fieldCandidateList, 01525 fieldCount, 01526 fieldAcceptList, 01527 fieldRejectList, 01528 depth, 01529 fieldNode.first + "/", // relativePathBase 01530 !i // launch inFirstRecord (or not) depth search 01531 ); 01532 } 01533 } 01534 } 01535 01536 //__COUT__ << "======================= check for count = " << 01537 // (int)recordList.size() << __E__; 01538 01539 // loop through all field candidates 01540 // remove those with <field count> != num of records 01541 for(unsigned int i = 0; i < fieldCandidateList.size(); ++i) 01542 { 01543 //__COUT__ << "Checking " << fieldCandidateList[i].relativePath_ << 01544 // fieldCandidateList[i].columnName_ << " = " << 01545 // fieldCount[i] << __E__; 01546 if(fieldCount[i] != -1 && fieldCount[i] != (int)recordList.size()) 01547 { 01548 //__COUT__ << "Erasing " << fieldCandidateList[i].relativePath_ << 01549 // fieldCandidateList[i].columnName_ << __E__; 01550 01551 fieldCount.erase(fieldCount.begin() + i); 01552 fieldCandidateList.erase(fieldCandidateList.begin() + i); 01553 --i; // rewind to look at next after deleted 01554 } 01555 } 01556 01557 // for(unsigned int i=0;i<fieldCandidateList.size();++i) 01558 // __COUT__ << "Final " << fieldCandidateList[i].relativePath_ << 01559 // fieldCandidateList[i].columnName_ << __E__; 01560 01561 return fieldCandidateList; 01562 } //end getCommonFields() 01563 01564 //============================================================================== 01565 // getUniqueValuesForField 01566 // 01567 // returns sorted unique values for the specified records and field 01568 // 01569 std::set<std::string /*unique-value*/> ConfigurationTree::getUniqueValuesForField( 01570 const std::vector<std::string /*relative-path*/>& recordList, 01571 const std::string& fieldName) const 01572 { 01573 // enforce that starting point is a table node 01574 if(!isConfigurationNode()) 01575 { 01576 __SS__ << "Can only get getCommonFields from a table node! " 01577 << "The node type is " << getNodeType() << __E__; 01578 01579 ss << nodeDump() << __E__; 01580 __SS_THROW__; 01581 } 01582 01583 std::set<std::string /*unique-value*/> uniqueValues; 01584 01585 // for each record in <record list> 01586 // emplace value at field into set 01587 // 01588 // return result 01589 01590 for(unsigned int i = 0; i < recordList.size(); ++i) 01591 { 01592 __COUT__ << "Checking " << recordList[i] << __E__; 01593 01594 // Note: that ConfigurationTree maps both fields associated with a link 01595 // to the same node instance. 01596 // The behavior is likely not expected as response for this function.. 01597 // so for links return actual value for field name specified 01598 // i.e. if Table of link is requested give that; if linkID is requested give 01599 // that. use TRUE in getValueAsString for proper behavior 01600 uniqueValues.emplace( 01601 getNode(recordList[i]).getNode(fieldName).getValueAsString(true)); 01602 } 01603 01604 return uniqueValues; 01605 } //end getUniqueValuesForField() 01606 01607 //============================================================================== 01608 // recursiveGetCommonFields 01609 // wrapper is ...getCommonFields 01610 void ConfigurationTree::recursiveGetCommonFields( 01611 std::vector<ConfigurationTree::RecordField>& fieldCandidateList, 01612 std::vector<int>& fieldCount, 01613 const std::vector<std::string /*relative-path*/>& fieldAcceptList, 01614 const std::vector<std::string /*relative-path*/>& fieldRejectList, 01615 unsigned int depth, 01616 const std::string& relativePathBase, 01617 bool inFirstRecord) const 01618 { 01619 --depth; 01620 //__COUT__ << "relativePathBase " << relativePathBase << __E__; 01621 01622 // ===================== 01623 // Start recursiveGetCommonFields() 01624 // --depth; 01625 // loop through all children 01626 // if isValueNode (value nodes are possible field candidates!) 01627 // if first uid record 01628 // add field to <field candidates list> if in <field filter list> 01629 // initial mark <field count> as 1 01630 // else 01631 // if field is in list, 01632 // increment count for field candidate 01633 // //?increment fields in list count for record 01634 // else if field is not in list, discard field 01635 // else if depth > 0 and is UID-Link 01636 // if Link Table/UID pair is not found in <field candidates list> (avoid 01637 // endless loops through tree) recursiveGetCommonFields() 01638 // ===================== 01639 01640 bool found; // used in loops 01641 auto tableName = getTableName(); // all fields will share this table name 01642 auto uid = getUIDAsString(); // all fields will share this uid 01643 unsigned int j; 01644 01645 auto recordChildren = getChildren(); 01646 for(const auto& fieldNode : recordChildren) 01647 { 01648 if(fieldNode.second.isValueNode()) 01649 { 01650 // skip author and record insertion time 01651 if(fieldNode.second.getColumnInfo().getType() == 01652 TableViewColumnInfo::TYPE_AUTHOR || 01653 fieldNode.second.getColumnInfo().getType() == 01654 TableViewColumnInfo::TYPE_TIMESTAMP) 01655 continue; 01656 01657 //__COUT__ << "isValueNode " << fieldNode.first << __E__; 01658 if(inFirstRecord) // first uid record 01659 { 01660 // check field accept filter list 01661 found = fieldAcceptList.size() ? false : true; // accept if no filter 01662 // list 01663 for(const auto& fieldFilter : fieldAcceptList) 01664 if(StringMacros::wildCardMatch(fieldFilter, fieldNode.first)) 01665 { 01666 found = true; 01667 break; 01668 } 01669 01670 if(found) 01671 { 01672 // check field reject filter list 01673 01674 found = true; // accept if no filter list 01675 for(const auto& fieldFilter : fieldRejectList) 01676 if(StringMacros::wildCardMatch(fieldFilter, fieldNode.first)) 01677 { 01678 found = false; // reject if match 01679 break; 01680 } 01681 } 01682 01683 // if found, new field (since this is first record) 01684 if(found) 01685 { 01686 //__COUT__ << "FOUND field " << 01687 // (relativePathBase + fieldNode.first) << __E__; 01688 fieldCandidateList.push_back(ConfigurationTree::RecordField( 01689 tableName, 01690 uid, 01691 fieldNode.first, 01692 relativePathBase, // relative path, not including columnName_ 01693 &fieldNode.second.getColumnInfo())); 01694 fieldCount.push_back(1); // init count to 1 01695 } 01696 } 01697 else // not first record 01698 { 01699 // if field is in <field candidates list>, increment <field count> 01700 // else ignore 01701 for(j = 0; j < fieldCandidateList.size(); ++j) 01702 { 01703 if((relativePathBase + fieldNode.first) == 01704 (fieldCandidateList[j].relativePath_ + 01705 fieldCandidateList[j].columnName_)) 01706 { 01707 //__COUT__ << "incrementing " << j << 01708 // " " << fieldCandidateList[j].relativePath_ << __E__; 01709 // found, so increment <field count> 01710 ++fieldCount[j]; 01711 break; 01712 } 01713 } 01714 } 01715 } 01716 else if(depth > 0 && fieldNode.second.isUIDLinkNode() && 01717 !fieldNode.second.isDisconnected()) 01718 { 01719 //__COUT__ << "isUIDLinkNode " << (relativePathBase + fieldNode.first) << 01720 // __E__; 01721 fieldNode.second.recursiveGetCommonFields( 01722 fieldCandidateList, 01723 fieldCount, 01724 fieldAcceptList, 01725 fieldRejectList, 01726 depth, 01727 (relativePathBase + fieldNode.first) + "/", // relativePathBase 01728 inFirstRecord // continue inFirstRecord (or not) depth search 01729 ); 01730 } 01731 } 01732 } //end recursiveGetCommonFields() 01733 01734 //============================================================================== 01735 // getChildrenByPriority 01736 // returns them in order encountered in the table 01737 // if filterMap criteria, then rejects any that do not meet all criteria 01738 // 01739 // value can be comma-separated for OR of multiple values 01740 std::vector<std::vector<std::pair<std::string, ConfigurationTree>>> 01741 ConfigurationTree::getChildrenByPriority( 01742 std::map<std::string /*relative-path*/, std::string /*value*/> filterMap, 01743 bool onlyStatusTrue) const 01744 { 01745 std::vector<std::vector<std::pair<std::string, ConfigurationTree>>> retVector; 01746 01747 //__COUT__ << "Children of node: " << getValueAsString() << __E__; 01748 01749 bool filtering = filterMap.size(); 01750 bool skip; 01751 std::string fieldValue; 01752 01753 bool createContainer; 01754 01755 std::vector<std::vector<std::string>> childrenNamesByPriority = 01756 getChildrenNamesByPriority(onlyStatusTrue); 01757 01758 for(auto& childNamesAtPriority : childrenNamesByPriority) 01759 { 01760 createContainer = true; 01761 01762 for(auto& childName : childNamesAtPriority) 01763 { 01764 //__COUT__ << "\tChild: " << childName << __E__; 01765 01766 if(filtering) 01767 { 01768 // if all criteria are not met, then skip 01769 skip = false; 01770 01771 // for each filter, check value 01772 for(const auto& filterPair : filterMap) 01773 { 01774 std::string filterPath = childName + "/" + filterPair.first; 01775 __COUTV__(filterPath); 01776 try 01777 { 01778 // extract field value list 01779 std::vector<std::string> fieldValues; 01780 StringMacros::getVectorFromString( 01781 filterPair.second, 01782 fieldValues, 01783 std::set<char>({','}) /*delimiters*/); 01784 01785 __COUTV__(fieldValues.size()); 01786 01787 skip = true; 01788 // for each field check if any match 01789 for(const auto& fieldValue : fieldValues) 01790 { 01791 // Note: that ConfigurationTree maps both fields associated 01792 // with a link to the same node instance. The behavior is 01793 // likely not expected as response for this function.. so for 01794 // links return actual value for field name specified i.e. 01795 // if Table of link is requested give that; if linkID is 01796 // requested give that. use TRUE in getValueAsString for 01797 // proper 01798 // behavior 01799 01800 __COUT__ << "\t\tCheck: " << filterPair.first 01801 << " == " << fieldValue << " => " 01802 << StringMacros::decodeURIComponent(fieldValue) 01803 << " ??? " 01804 << this->getNode(filterPath).getValueAsString(true) 01805 << __E__; 01806 01807 if(StringMacros::wildCardMatch( 01808 StringMacros::decodeURIComponent(fieldValue), 01809 this->getNode(filterPath).getValueAsString(true))) 01810 { 01811 // found a match for the field/value pair 01812 skip = false; 01813 break; 01814 } 01815 } 01816 } 01817 catch(...) 01818 { 01819 __SS__ << "Failed to access filter path '" << filterPath 01820 << "' - aborting." << __E__; 01821 01822 ss << nodeDump() << __E__; 01823 __SS_THROW__; 01824 } 01825 01826 if(skip) 01827 break; // no match for this field, so stop checking and skip this 01828 // record 01829 } 01830 01831 if(skip) 01832 continue; // skip this record 01833 01834 //__COUT__ << "\tChild accepted: " << childName << __E__; 01835 } 01836 01837 if(createContainer) 01838 { 01839 retVector.push_back( 01840 std::vector<std::pair<std::string, ConfigurationTree>>()); 01841 createContainer = false; 01842 } 01843 01844 retVector[retVector.size() - 1].push_back( 01845 std::pair<std::string, ConfigurationTree>( 01846 childName, this->getNode(childName, true))); 01847 } // end children within priority loop 01848 } // end children by priority loop 01849 01850 //__COUT__ << "Done w/Children of node: " << getValueAsString() << __E__; 01851 return retVector; 01852 } // end getChildrenByPriority() 01853 01854 //============================================================================== 01855 // getChildren 01856 // returns them in order encountered in the table 01857 // if filterMap criteria, then rejects any that do not meet all criteria 01858 // 01859 // value can be comma-separated for OR of multiple values 01860 std::vector<std::pair<std::string, ConfigurationTree>> ConfigurationTree::getChildren( 01861 std::map<std::string /*relative-path*/, std::string /*value*/> filterMap, 01862 bool byPriority, 01863 bool onlyStatusTrue) const 01864 { 01865 std::vector<std::pair<std::string, ConfigurationTree>> retVector; 01866 01867 //__COUT__ << "Children of node: " << getValueAsString() << __E__; 01868 01869 bool filtering = filterMap.size(); 01870 bool skip; 01871 std::string fieldValue; 01872 01873 std::vector<std::string> childrenNames = getChildrenNames(byPriority, onlyStatusTrue); 01874 for(auto& childName : childrenNames) 01875 { 01876 //__COUT__ << "\tChild: " << childName << __E__; 01877 01878 if(filtering) 01879 { 01880 // if all criteria are not met, then skip 01881 skip = false; 01882 01883 // for each filter, check value 01884 for(const auto& filterPair : filterMap) 01885 { 01886 std::string filterPath = childName + "/" + filterPair.first; 01887 __COUTV__(filterPath); 01888 try 01889 { 01890 // extract field value list 01891 std::vector<std::string> fieldValues; 01892 StringMacros::getVectorFromString( 01893 filterPair.second, 01894 fieldValues, 01895 std::set<char>({','}) /*delimiters*/); 01896 01897 __COUTV__(fieldValues.size()); 01898 01899 skip = true; 01900 // for each field check if any match 01901 for(const auto& fieldValue : fieldValues) 01902 { 01903 // Note: that ConfigurationTree maps both fields associated with a 01904 // link to the same node instance. The behavior is likely not 01905 // expected as response for this function.. so for links 01906 // return 01907 // actual value for field name specified i.e. if Table of link 01908 // is requested give that; if linkID is requested give that. use 01909 // TRUE in getValueAsString for proper behavior 01910 01911 __COUT__ 01912 << "\t\tCheck: " << filterPair.first << " == " << fieldValue 01913 << " => " << StringMacros::decodeURIComponent(fieldValue) 01914 << " ??? " << this->getNode(filterPath).getValueAsString(true) 01915 << __E__; 01916 01917 if(StringMacros::wildCardMatch( 01918 StringMacros::decodeURIComponent(fieldValue), 01919 this->getNode(filterPath).getValueAsString(true))) 01920 { 01921 // found a match for the field/value pair 01922 skip = false; 01923 break; 01924 } 01925 } 01926 } 01927 catch(...) 01928 { 01929 __SS__ << "Failed to access filter path '" << filterPath 01930 << "' - aborting." << __E__; 01931 01932 ss << nodeDump() << __E__; 01933 __SS_THROW__; 01934 } 01935 01936 if(skip) 01937 break; // no match for this field, so stop checking and skip this 01938 // record 01939 } 01940 01941 if(skip) 01942 continue; // skip this record 01943 01944 //__COUT__ << "\tChild accepted: " << childName << __E__; 01945 } 01946 01947 retVector.push_back(std::pair<std::string, ConfigurationTree>( 01948 childName, this->getNode(childName, true))); 01949 } 01950 01951 //__COUT__ << "Done w/Children of node: " << getValueAsString() << __E__; 01952 return retVector; 01953 } //end getChildren() 01954 01955 //============================================================================== 01956 // getChildren 01957 // returns them in order encountered in the table 01958 std::map<std::string, ConfigurationTree> ConfigurationTree::getChildrenMap(void) const 01959 { 01960 std::map<std::string, ConfigurationTree> retMap; 01961 01962 //__COUT__ << "Children of node: " << getValueAsString() << __E__; 01963 01964 std::vector<std::string> childrenNames = getChildrenNames(); 01965 for(auto& childName : childrenNames) 01966 { 01967 //__COUT__ << "\tChild: " << childName << __E__; 01968 retMap.insert(std::pair<std::string, ConfigurationTree>( 01969 childName, this->getNode(childName))); 01970 } 01971 01972 //__COUT__ << "Done w/Children of node: " << getValueAsString() << __E__; 01973 return retMap; 01974 } //end getChildrenMap() 01975 01976 //============================================================================== 01977 bool ConfigurationTree::isRootNode(void) const { return (!table_); } 01978 01979 //============================================================================== 01980 bool ConfigurationTree::isConfigurationNode(void) const 01981 { 01982 return (table_ && row_ == TableView::INVALID && col_ == TableView::INVALID); 01983 } 01984 01985 //============================================================================== 01986 // getChildrenNamesByPriority 01987 // returns them in priority order encountered in the table 01988 std::vector<std::vector<std::string>> ConfigurationTree::getChildrenNamesByPriority( 01989 bool onlyStatusTrue) const 01990 { 01991 std::vector<std::vector<std::string /*child name*/>> retVector; 01992 01993 if(!tableView_) 01994 { 01995 __SS__ << "Can not get children names of '" << getValueAsString() 01996 << "' with null configuration view pointer!" << __E__; 01997 if(isLinkNode() && isDisconnected()) 01998 ss << " This node is a disconnected link to " << getDisconnectedTableName() 01999 << __E__; 02000 02001 ss << nodeDump() << __E__; 02002 __SS_ONLY_THROW__; 02003 } 02004 02005 if(row_ == TableView::INVALID && col_ == TableView::INVALID) 02006 { 02007 // this node is config node 02008 // so return all uid node strings that match groupId 02009 02010 bool tmpStatus; 02011 02012 if(1) // reshuffle by priority 02013 { 02014 try 02015 { 02016 std::map<uint64_t /*priority*/, std::vector<unsigned int /*child row*/>> 02017 orderedByPriority; 02018 std::vector<std::string /*child name*/> retPrioritySet; 02019 02020 unsigned int col = tableView_->getColPriority(); 02021 02022 uint64_t tmpPriority; 02023 02024 for(unsigned int r = 0; r < tableView_->getNumberOfRows(); ++r) 02025 if(groupId_ == "" || 02026 tableView_->isEntryInGroup(r, childLinkIndex_, groupId_)) 02027 { 02028 // check status if needed 02029 if(onlyStatusTrue) 02030 { 02031 tableView_->getValue( 02032 tmpStatus, r, tableView_->getColStatus()); 02033 if(!tmpStatus) 02034 continue; // skip those with status false 02035 } 02036 02037 tableView_->getValue(tmpPriority, r, col); 02038 // do not accept DEFAULT value of 0.. convert to 100 02039 orderedByPriority[tmpPriority ? tmpPriority : 100].push_back(r); 02040 } 02041 02042 // at this point have priority map 02043 // now build return vector 02044 02045 for(const auto& priorityChildRowVector : orderedByPriority) 02046 { 02047 retVector.push_back(std::vector<std::string /*child name*/>()); 02048 for(const auto& priorityChildRow : priorityChildRowVector.second) 02049 retVector[retVector.size() - 1].push_back( 02050 tableView_->getDataView()[priorityChildRow] 02051 [tableView_->getColUID()]); 02052 } 02053 02054 __COUT__ << "Returning priority children list." << __E__; 02055 return retVector; 02056 } 02057 catch(std::runtime_error& e) 02058 { 02059 __COUT_WARN__ << "Error identifying priority. Assuming all children have " 02060 "equal priority (Error: " 02061 << e.what() << __E__; 02062 retVector.clear(); 02063 } 02064 } 02065 // else not by priority 02066 02067 for(unsigned int r = 0; r < tableView_->getNumberOfRows(); ++r) 02068 if(groupId_ == "" || tableView_->isEntryInGroup(r, childLinkIndex_, groupId_)) 02069 { 02070 // check status if needed 02071 if(onlyStatusTrue) 02072 { 02073 tableView_->getValue(tmpStatus, r, tableView_->getColStatus()); 02074 if(!tmpStatus) 02075 continue; // skip those with status false 02076 } 02077 02078 retVector.push_back(std::vector<std::string /*child name*/>()); 02079 retVector[retVector.size() - 1].push_back( 02080 tableView_->getDataView()[r][tableView_->getColUID()]); 02081 } 02082 } 02083 else if(row_ == TableView::INVALID) 02084 { 02085 __SS__ << "Malformed ConfigurationTree" << __E__; 02086 02087 ss << nodeDump() << __E__; 02088 __SS_THROW__; 02089 } 02090 else if(col_ == TableView::INVALID) 02091 { 02092 // this node is uid node 02093 // so return all link and value nodes 02094 02095 for(unsigned int c = 0; c < tableView_->getNumberOfColumns(); ++c) 02096 if(c == tableView_->getColUID() || // skip UID and linkID columns (only show 02097 // link column, to avoid duplicates) 02098 tableView_->getColumnInfo(c).isChildLinkGroupID() || 02099 tableView_->getColumnInfo(c).isChildLinkUID()) 02100 continue; 02101 else 02102 { 02103 retVector.push_back(std::vector<std::string /*child name*/>()); 02104 retVector[retVector.size() - 1].push_back( 02105 tableView_->getColumnInfo(c).getName()); 02106 } 02107 } 02108 else // this node is value node, so has no node to choose from 02109 { 02110 // this node is value node, cant go any deeper! 02111 __SS__ << "\n\nError occurred looking for children of nodeName=" << getValueName() 02112 << "\n\n" 02113 << "Invalid depth! getChildrenValues() called from a value point in the " 02114 "Configuration Tree." 02115 << __E__; 02116 02117 ss << nodeDump() << __E__; 02118 __SS_THROW__; 02119 } 02120 02121 return retVector; 02122 } //end getChildrenNamesByPriority() 02123 02124 //============================================================================== 02125 // getChildrenNames 02126 // returns them in order encountered in the table 02127 std::vector<std::string> ConfigurationTree::getChildrenNames(bool byPriority, 02128 bool onlyStatusTrue) const 02129 { 02130 std::vector<std::string /*child name*/> retVector; 02131 02132 if(!tableView_) 02133 { 02134 __SS__ << "Can not get children names of '" << getValueAsString() 02135 << "' with null configuration view pointer!" << __E__; 02136 if(isLinkNode() && isDisconnected()) 02137 ss << " This node is a disconnected link to " << getDisconnectedTableName() 02138 << __E__; 02139 __SS_ONLY_THROW__; 02140 } 02141 02142 if(row_ == TableView::INVALID && col_ == TableView::INVALID) 02143 { 02144 // this node is config node 02145 // so return all uid node strings that match groupId 02146 02147 bool tmpStatus; 02148 02149 if(byPriority) // reshuffle by priority 02150 { 02151 try 02152 { 02153 std::map<uint64_t /*priority*/, std::vector<unsigned int /*child row*/>> 02154 orderedByPriority; 02155 std::vector<std::string /*child name*/> retPrioritySet; 02156 02157 unsigned int col = tableView_->getColPriority(); 02158 02159 uint64_t tmpPriority; 02160 02161 for(unsigned int r = 0; r < tableView_->getNumberOfRows(); ++r) 02162 if(groupId_ == "" || 02163 tableView_->isEntryInGroup(r, childLinkIndex_, groupId_)) 02164 { 02165 // check status if needed 02166 if(onlyStatusTrue) 02167 { 02168 tableView_->getValue( 02169 tmpStatus, r, tableView_->getColStatus()); 02170 if(!tmpStatus) 02171 continue; // skip those with status false 02172 } 02173 02174 tableView_->getValue(tmpPriority, r, col); 02175 // do not accept DEFAULT value of 0.. convert to 100 02176 orderedByPriority[tmpPriority ? tmpPriority : 100].push_back(r); 02177 } 02178 02179 // at this point have priority map 02180 // now build return vector 02181 02182 for(const auto& priorityChildRowVector : orderedByPriority) 02183 for(const auto& priorityChildRow : priorityChildRowVector.second) 02184 retVector.push_back( 02185 tableView_->getDataView()[priorityChildRow] 02186 [tableView_->getColUID()]); 02187 02188 __COUT__ << "Returning priority children list." << __E__; 02189 return retVector; 02190 } 02191 catch(std::runtime_error& e) 02192 { 02193 __COUT_WARN__ << "Priority configuration not found. Assuming all " 02194 "children have equal priority (Error: " 02195 << e.what() << __E__; 02196 retVector.clear(); 02197 } 02198 } 02199 // else not by priority 02200 02201 for(unsigned int r = 0; r < tableView_->getNumberOfRows(); ++r) 02202 if(groupId_ == "" || tableView_->isEntryInGroup(r, childLinkIndex_, groupId_)) 02203 { 02204 // check status if needed 02205 if(onlyStatusTrue) 02206 { 02207 tableView_->getValue(tmpStatus, r, tableView_->getColStatus()); 02208 if(!tmpStatus) 02209 continue; // skip those with status false 02210 } 02211 02212 retVector.push_back( 02213 tableView_->getDataView()[r][tableView_->getColUID()]); 02214 } 02215 } 02216 else if(row_ == TableView::INVALID) 02217 { 02218 __SS__ << "Malformed ConfigurationTree" << __E__; 02219 02220 ss << nodeDump() << __E__; 02221 __SS_THROW__; 02222 } 02223 else if(col_ == TableView::INVALID) 02224 { 02225 // this node is uid node 02226 // so return all link and value nodes 02227 02228 for(unsigned int c = 0; c < tableView_->getNumberOfColumns(); ++c) 02229 if(c == tableView_->getColUID() || // skip UID and linkID columns (only show 02230 // link column, to avoid duplicates) 02231 tableView_->getColumnInfo(c).isChildLinkGroupID() || 02232 tableView_->getColumnInfo(c).isChildLinkUID()) 02233 continue; 02234 else 02235 retVector.push_back(tableView_->getColumnInfo(c).getName()); 02236 } 02237 else // this node is value node, so has no node to choose from 02238 { 02239 // this node is value node, cant go any deeper! 02240 __SS__ << "\n\nError occurred looking for children of nodeName=" << getValueName() 02241 << "\n\n" 02242 << "Invalid depth! getChildrenValues() called from a value point in the " 02243 "Configuration Tree." 02244 << __E__; 02245 02246 ss << nodeDump() << __E__; 02247 __SS_THROW__; 02248 } 02249 02250 return retVector; 02251 } //end getChildrenNames() 02252 02253 //============================================================================== 02254 // getValueAsTreeNode 02255 // returns tree node for value of this node, treating the value 02256 // as a string for the absolute path string from root of tree 02257 ConfigurationTree ConfigurationTree::getValueAsTreeNode(void) const 02258 { 02259 // check if first character is a /, .. if so try to get value in tree 02260 // if exception, just take value 02261 // note: this call will throw an error, in effect, if not a "value" node 02262 if(!tableView_) 02263 { 02264 __SS__ << "Invalid node for get value." << __E__; 02265 __SS_THROW__; 02266 } 02267 02268 std::string valueString = 02269 tableView_->getValueAsString(row_, col_, true /* convertEnvironmentVariables */); 02270 //__COUT__ << valueString << __E__; 02271 if(valueString.size() && valueString[0] == '/') 02272 { 02273 //__COUT__ << "Starts with '/' - check if valid tree path: " << valueString << 02274 // __E__; 02275 try 02276 { 02277 ConfigurationTree retNode = configMgr_->getNode(valueString); 02278 __COUT__ << "Found a valid tree path in value!" << __E__; 02279 return retNode; 02280 } 02281 catch(...) 02282 { 02283 __SS__ << "Invalid tree path." << __E__; 02284 __SS_ONLY_THROW__; 02285 } 02286 } 02287 02288 { 02289 __SS__ << "Invalid value string '" << valueString 02290 << "' - must start with a '/' character." << __E__; 02291 __SS_ONLY_THROW__; 02292 } 02293 } //end getValueAsTreeNode()