EnvironmentNode.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2017 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "EnvironmentNode.hpp"
  14. #include "Exceptions.hpp"
  15. #include "Utils.hpp"
  16. #include "ConfigPath.hpp"
  17. #include "EnvironmentMgr.hpp"
  18. void EnvironmentNode::addChild(std::shared_ptr<EnvironmentNode> pNode)
  19. {
  20. m_children.insert(std::make_pair(pNode->getName(), pNode));
  21. }
  22. bool EnvironmentNode::removeChild(const std::shared_ptr<EnvironmentNode> pNode, std::vector<std::string> &removedNodeIds)
  23. {
  24. bool removed = false;
  25. for (auto it=m_children.begin(); it!= m_children.end() && !removed; ++it)
  26. {
  27. if (pNode == it->second)
  28. {
  29. pNode->removeAllChildren(removedNodeIds);
  30. removedNodeIds.emplace_back(pNode->getId());
  31. m_children.erase(it);
  32. removed = true;
  33. }
  34. }
  35. return removed;
  36. }
  37. void EnvironmentNode::removeAllChildren(std::vector<std::string> &removedNodeIds)
  38. {
  39. for (auto &childNodeIt: m_children)
  40. {
  41. childNodeIt.second->removeAllChildren(removedNodeIds);
  42. removedNodeIds.emplace_back(childNodeIt.second->getId());
  43. }
  44. m_children.clear();
  45. }
  46. bool EnvironmentNode::addAttribute(const std::string &name, std::shared_ptr<EnvironmentValue> pValue)
  47. {
  48. auto retValue = m_attributes.insert(std::make_pair(name, pValue));
  49. return retValue.second;
  50. }
  51. void EnvironmentNode::getChildren(std::vector<std::shared_ptr<EnvironmentNode>> &childNodes, const std::string &name) const
  52. {
  53. if (name.empty())
  54. {
  55. for (auto nodeIt = m_children.begin(); nodeIt != m_children.end(); ++nodeIt)
  56. {
  57. childNodes.push_back(nodeIt->second);
  58. }
  59. }
  60. else
  61. {
  62. auto rangeIt = m_children.equal_range(name);
  63. for (auto it = rangeIt.first; it != rangeIt.second; ++it)
  64. {
  65. childNodes.push_back(it->second);
  66. }
  67. }
  68. }
  69. std::shared_ptr<EnvironmentNode> EnvironmentNode::getParent() const
  70. {
  71. std::shared_ptr<EnvironmentNode> pParent;
  72. if (!m_pParent.expired())
  73. {
  74. pParent = m_pParent.lock();
  75. }
  76. return pParent;
  77. }
  78. void EnvironmentNode::getAttributes(std::vector<std::shared_ptr<EnvironmentValue>> &attrs) const
  79. {
  80. for (auto attrIt = m_attributes.begin(); attrIt != m_attributes.end(); ++attrIt)
  81. {
  82. attrs.push_back(attrIt->second);
  83. }
  84. }
  85. void EnvironmentNode::addMissingAttributesFromConfig()
  86. {
  87. std::vector<std::shared_ptr<SchemaValue>> configuredAttributes;
  88. m_pSchemaItem->getAttributes(configuredAttributes);
  89. //
  90. // go through all the configured attrubutes and for each that is not present in our list, add it
  91. for (auto it = configuredAttributes.begin(); it != configuredAttributes.end(); ++it)
  92. {
  93. auto attrIt = m_attributes.find((*it)->getName());
  94. if (attrIt == m_attributes.end())
  95. {
  96. std::shared_ptr<SchemaValue> pCfgValue = *it;
  97. std::shared_ptr<EnvironmentValue> pEnvValue = std::make_shared<EnvironmentValue>(shared_from_this(), pCfgValue, pCfgValue->getName());
  98. pCfgValue->addEnvironmentValue(pEnvValue);
  99. addAttribute(pCfgValue->getName(), pEnvValue);
  100. }
  101. }
  102. }
  103. void EnvironmentNode::setAttributeValues(const std::vector<NameValue> &values, Status &status, bool allowInvalid, bool forceCreate)
  104. {
  105. for (auto it = values.begin(); it != values.end(); ++it)
  106. {
  107. setAttributeValue((*it).name, (*it).value, status, allowInvalid, forceCreate);
  108. }
  109. }
  110. void EnvironmentNode::setAttributeValue(const std::string &attrName, const std::string &value, Status &status, bool allowInvalid, bool forceCreate)
  111. {
  112. std::shared_ptr<EnvironmentValue> pEnvValue;
  113. auto it = m_attributes.find(attrName);
  114. if (it != m_attributes.end())
  115. {
  116. pEnvValue = it->second;
  117. }
  118. //
  119. // Not found on this node. See if the configuration defines the attribute. If so, set the value and move on.
  120. // If not and the forceCreate flag is set, create it.
  121. else if (forceCreate)
  122. {
  123. std::shared_ptr<SchemaValue> pCfgValue = m_pSchemaItem->getAttribute(attrName);
  124. pEnvValue = std::make_shared<EnvironmentValue>(shared_from_this(), pCfgValue, attrName);
  125. addAttribute(attrName, pEnvValue);
  126. if (!pCfgValue->isDefined())
  127. {
  128. status.addMsg(statusMsg::warning, getId(), attrName, "Undefined attribute did not exist in configuration, was created");
  129. }
  130. }
  131. if (pEnvValue)
  132. {
  133. pEnvValue->setValue(value, &status, allowInvalid);
  134. }
  135. else
  136. {
  137. status.addMsg(statusMsg::error, getId(), attrName, "The attribute does not exist and was not created");
  138. }
  139. }
  140. std::string EnvironmentNode::getAttributeValue(const std::string &name) const
  141. {
  142. std::string value;
  143. std::shared_ptr<EnvironmentValue> pAttribute = getAttribute(name);
  144. if (pAttribute)
  145. value = pAttribute->getValue();
  146. return value;
  147. }
  148. bool EnvironmentNode::setLocalValue(const std::string &newValue, Status &status, bool force)
  149. {
  150. bool rc = false;
  151. //
  152. // If no environment value is present, create one first
  153. if (!m_pLocalValue)
  154. {
  155. std::shared_ptr<SchemaValue> pCfgValue = m_pSchemaItem->getItemSchemaValue();
  156. m_pLocalValue = std::make_shared<EnvironmentValue>(shared_from_this(), pCfgValue, ""); // node's value has no name
  157. }
  158. rc = m_pLocalValue->setValue(newValue, &status, force);
  159. return rc;
  160. }
  161. std::string EnvironmentNode::getLocalValue() const
  162. {
  163. std::string value;
  164. if (m_pLocalValue)
  165. {
  166. value = m_pLocalValue->getValue();
  167. }
  168. return value;
  169. }
  170. void EnvironmentNode::validate(Status &status, bool includeChildren, bool includeHiddenNodes) const
  171. {
  172. if (!m_pSchemaItem->isHidden() || includeHiddenNodes)
  173. {
  174. //
  175. // Check node value
  176. if (m_pLocalValue)
  177. {
  178. m_pLocalValue->validate(status, m_id);
  179. }
  180. //
  181. // Check any attributes
  182. for (auto attrIt = m_attributes.begin(); attrIt != m_attributes.end(); ++attrIt)
  183. {
  184. attrIt->second->validate(status, m_id);
  185. //
  186. // If this value must be unique, make sure it is
  187. if (attrIt->second->getSchemaValue()->isUniqueValue())
  188. {
  189. bool found = false;
  190. std::vector<std::string> allValues;
  191. attrIt->second->getAllValuesForSiblings(allValues);
  192. std::set<std::string> unquieValues;
  193. for (auto it = allValues.begin(); it != allValues.end() && !found; ++it)
  194. {
  195. auto ret = unquieValues.insert(*it);
  196. found = !ret.second;
  197. }
  198. if (found)
  199. {
  200. status.addUniqueMsg(statusMsg::error, m_id, attrIt->second->getName(), "Attribute value must be unique");
  201. }
  202. }
  203. //
  204. // Does this value need to be from another set of values?
  205. if (attrIt->second->getSchemaValue()->isFromUniqueValueSet())
  206. {
  207. bool found = false;
  208. std::vector<std::string> allValues;
  209. attrIt->second->getSchemaValue()->getAllKeyRefValues(allValues);
  210. for (auto it = allValues.begin(); it != allValues.end() && !found; ++it)
  211. found = *it == attrIt->second->getValue();
  212. if (!found)
  213. {
  214. status.addMsg(statusMsg::error, m_id, attrIt->second->getName(), "Attribute value must be from a unique set");
  215. }
  216. }
  217. }
  218. //
  219. // Now check all children
  220. if (includeChildren)
  221. {
  222. for (auto childIt = m_children.begin(); childIt != m_children.end(); ++childIt)
  223. {
  224. childIt->second->validate(status, includeChildren, includeHiddenNodes);
  225. }
  226. }
  227. }
  228. }
  229. void EnvironmentNode::getAttributeValueForAllSiblings(const std::string &attrName, std::vector<std::string> &result) const
  230. {
  231. std::shared_ptr<EnvironmentNode> pParentNode = m_pParent.lock();
  232. if (pParentNode)
  233. {
  234. std::vector<std::shared_ptr<EnvironmentNode>> nodes;
  235. pParentNode->getChildren(nodes, m_name);
  236. for (auto it = nodes.begin(); it != nodes.end(); ++it)
  237. {
  238. result.push_back((*it)->getAttributeValue(attrName));
  239. }
  240. }
  241. }
  242. const std::shared_ptr<EnvironmentValue> EnvironmentNode::getAttribute(const std::string &name) const
  243. {
  244. std::shared_ptr<EnvironmentValue> pValue;
  245. auto it = m_attributes.find(name);
  246. if (it != m_attributes.end())
  247. {
  248. pValue = it->second;
  249. }
  250. return pValue;
  251. }
  252. void EnvironmentNode::getInsertableItems(std::vector<InsertableItem> &insertableItems) const
  253. {
  254. std::map<std::string, unsigned> childCounts;
  255. //
  256. // Iterate over the children and for each, create a childCount entry based on the
  257. // child node's configuration type
  258. for (auto childIt = m_children.begin(); childIt != m_children.end(); ++childIt)
  259. {
  260. std::string itemType = childIt->second->getSchemaItem()->getItemType();
  261. auto findIt = childCounts.find(itemType);
  262. if (findIt != childCounts.end())
  263. {
  264. ++findIt->second; // increment the number of instances of this item type.
  265. }
  266. else
  267. {
  268. childCounts.insert({ itemType, 1 });
  269. }
  270. }
  271. //
  272. // Now get the full list of configurable items, then resolve it against the child counts from
  273. // above to build a vector of insertable items
  274. std::vector<std::shared_ptr<SchemaItem>> configChildren;
  275. m_pSchemaItem->getChildren(configChildren);
  276. for (auto &pCfgItem: configChildren)
  277. {
  278. auto findIt = childCounts.find(pCfgItem->getItemType());
  279. if (findIt != childCounts.end())
  280. {
  281. if (findIt->second < pCfgItem->getMaxInstances())
  282. {
  283. insertableItems.push_back(InsertableItem(shared_from_this(), pCfgItem));
  284. }
  285. }
  286. else
  287. {
  288. insertableItems.push_back(InsertableItem(shared_from_this(), pCfgItem));
  289. }
  290. }
  291. }
  292. //
  293. // Called to initialize a newly added node to the environment (not just read from the environment)
  294. void EnvironmentNode::initialize()
  295. {
  296. //
  297. // Add missing attributes
  298. addMissingAttributesFromConfig();
  299. //
  300. // If we are a component and there is a buildSet attribute, set the value to the configItem's type
  301. if (!(m_pSchemaItem->getProperty("itemType").empty()) && hasAttribute("buildSet"))
  302. {
  303. Status status;
  304. setAttributeValue("buildSet", m_pSchemaItem->getProperty("itemType"), status);
  305. }
  306. //
  307. // Initilize each attribute
  308. for (auto attrIt = m_attributes.begin(); attrIt != m_attributes.end(); ++attrIt)
  309. {
  310. attrIt->second->initialize();
  311. }
  312. }
  313. void EnvironmentNode::fetchNodes(const std::string &path, std::vector<std::shared_ptr<EnvironmentNode>> &nodes) const
  314. {
  315. ConfigPath configPath(path);
  316. doFetchNodes(configPath, nodes);
  317. }
  318. void EnvironmentNode::doFetchNodes(ConfigPath &configPath, std::vector<std::shared_ptr<EnvironmentNode>> &nodes) const
  319. {
  320. std::shared_ptr<ConfigPathItem> pPathItem = configPath.getNextPathItem();
  321. if (pPathItem)
  322. {
  323. if (pPathItem->isRoot())
  324. {
  325. std::shared_ptr<const EnvironmentNode> pRoot = getRoot();
  326. if (pRoot->getName() == pPathItem->getElementName())
  327. {
  328. pRoot->doFetchNodes(configPath, nodes);
  329. }
  330. else
  331. {
  332. throw new ParseException("Invalid root element name ('" + pPathItem->getElementName() + "') specified in path");
  333. }
  334. }
  335. else if (pPathItem->isParentPathtItem())
  336. {
  337. getParent()->doFetchNodes(configPath, nodes);
  338. }
  339. else if (pPathItem->isCurrentPathItem())
  340. {
  341. doFetchNodes(configPath, nodes);
  342. }
  343. else
  344. {
  345. //
  346. // Get children nodes matching path element name (if no name, all children are returned)
  347. std::vector<std::shared_ptr<EnvironmentNode>> childNodes;
  348. getChildren(childNodes, pPathItem->getElementName());
  349. //
  350. // If there is an attribute and/or attribute values, search the child nodes from above
  351. if (!pPathItem->getAttributeName().empty())
  352. {
  353. std::string attrName = pPathItem->getAttributeName();
  354. auto childNodeIt = childNodes.begin();
  355. while (childNodeIt != childNodes.end())
  356. {
  357. //
  358. // If an attribute, then search attributes for those with the specified name, otherwise
  359. // get the schema item for this node and see if it has a property with the specified name.
  360. // In each case, if there is a value, check it too
  361. if (!pPathItem->isSchemaItem())
  362. {
  363. std::shared_ptr<EnvironmentValue> pAttribute = (*childNodeIt)->getAttribute(attrName);
  364. if (pAttribute && pAttribute->isValueSet())
  365. {
  366. if (pPathItem->checkValueAgainstValueList(pAttribute->getValue(), true))
  367. {
  368. ++childNodeIt;
  369. }
  370. else
  371. {
  372. childNodeIt = childNodes.erase(childNodeIt);
  373. }
  374. }
  375. else
  376. {
  377. childNodeIt = childNodes.erase(childNodeIt);
  378. }
  379. }
  380. else
  381. {
  382. std::shared_ptr<SchemaItem> pSchemaItem = (*childNodeIt)->getSchemaItem();
  383. std::string propertyValue = (attrName == "itemType") ? pSchemaItem->getItemType() : pSchemaItem->getProperty(attrName);
  384. if (pPathItem->checkValueAgainstValueList(propertyValue, true))
  385. {
  386. ++childNodeIt;
  387. }
  388. else
  389. {
  390. childNodeIt = childNodes.erase(childNodeIt);
  391. }
  392. }
  393. }
  394. }
  395. if (configPath.isPathRemaining())
  396. {
  397. //
  398. // For all the matching nodes at this element, call each to continue the search
  399. for (auto childNodeIt = childNodes.begin(); childNodeIt != childNodes.end(); ++childNodeIt)
  400. {
  401. (*childNodeIt)->doFetchNodes(configPath, nodes);
  402. }
  403. }
  404. else
  405. {
  406. nodes.insert(nodes.end(), childNodes.begin(), childNodes.end());
  407. }
  408. }
  409. }
  410. }
  411. std::shared_ptr<const EnvironmentNode> EnvironmentNode::getRoot() const
  412. {
  413. if (!m_pParent.expired())
  414. {
  415. return m_pParent.lock()->getRoot();
  416. }
  417. std::shared_ptr <const EnvironmentNode> ptr = shared_from_this();
  418. return ptr;
  419. }