SchemaItem.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  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 "SchemaItem.hpp"
  14. #include "Exceptions.hpp"
  15. #include "SchemaTypeStringLimits.hpp"
  16. #include "SchemaTypeIntegerLimits.hpp"
  17. #include <algorithm>
  18. #include "Utils.hpp"
  19. #include "EnvironmentNode.hpp"
  20. SchemaItem::SchemaItem(const std::string &name, const std::string &className, const std::shared_ptr<SchemaItem> &pParent) :
  21. m_pParent(pParent),
  22. m_hidden(false),
  23. m_minInstances(1),
  24. m_maxInstances(1)
  25. {
  26. //
  27. // Set property defaults
  28. m_properties["name"] = name;
  29. m_properties["displayName"] = name;
  30. m_properties["className"] = className;
  31. //
  32. // If this is a default schema item, allow any number of them
  33. if (className == "default")
  34. {
  35. m_minInstances = 0;
  36. m_maxInstances = UINT_MAX;
  37. }
  38. //
  39. // If this is a root node (no parent), then do some additional init
  40. if (m_pParent.expired())
  41. {
  42. //
  43. // Create a default type so that all values have a type
  44. std::shared_ptr<SchemaType> pDefaultType = std::make_shared<SchemaType>("default");
  45. pDefaultType->setBaseType("string");
  46. std::shared_ptr<SchemaTypeLimits> pDefaultLimits = std::make_shared<SchemaTypeLimits>();
  47. pDefaultType->setLimits(pDefaultLimits);
  48. addSchemaValueType(pDefaultType);
  49. }
  50. }
  51. SchemaItem::SchemaItem(const SchemaItem &item)
  52. {
  53. //
  54. // Copy stuff that doesn't have to be unique
  55. m_hidden = item.m_hidden;
  56. m_maxInstances = item.m_maxInstances;
  57. m_minInstances = item.m_minInstances;
  58. m_properties = item.m_properties;
  59. m_types = item.m_types;
  60. m_schemaTypes = item.m_schemaTypes;
  61. if (m_pItemValue)
  62. m_pItemValue = std::make_shared<SchemaValue>(*(item.m_pItemValue)); // copy constructed
  63. //
  64. // Make a copy of the children now
  65. for (auto &pChild: m_children)
  66. {
  67. addChild(std::make_shared<SchemaItem>(*pChild));
  68. }
  69. //
  70. // Copy the attributes
  71. for (auto attrIt = item.m_attributes.begin(); attrIt != item.m_attributes.end(); ++attrIt)
  72. {
  73. addAttribute(std::make_shared<SchemaValue>(*(attrIt->second)));
  74. }
  75. //
  76. // Event handlers
  77. m_eventHandlers = item.m_eventHandlers;
  78. m_uniqueAttributeValueSetReferences = item.m_uniqueAttributeValueSetReferences;
  79. m_uniqueAttributeValueSetDefs = item.m_uniqueAttributeValueSetDefs;
  80. m_requiredInstanceComponents = item.m_requiredInstanceComponents;
  81. }
  82. void SchemaItem::addSchemaValueType(const std::shared_ptr<SchemaType> &pType)
  83. {
  84. auto it = m_types.find(pType->getName());
  85. if (it == m_types.end())
  86. {
  87. m_types[pType->getName()] = pType;
  88. }
  89. else
  90. {
  91. throw(ParseException("Element: " + getProperty("name") + ", duplicate schema value type found: " + pType->getName()));
  92. }
  93. }
  94. std::shared_ptr<SchemaType> SchemaItem::getSchemaValueType(const std::string &typeName, bool throwIfNotPresent) const
  95. {
  96. std::shared_ptr<SchemaType> pType;
  97. auto it = m_types.find(typeName);
  98. if (it != m_types.end())
  99. {
  100. return it->second;
  101. }
  102. else
  103. {
  104. std::shared_ptr<SchemaItem> pParent = m_pParent.lock();
  105. if (pParent)
  106. {
  107. return pParent->getSchemaValueType(typeName, throwIfNotPresent);
  108. }
  109. }
  110. //
  111. // Did not find the type
  112. if (throwIfNotPresent)
  113. {
  114. std::string msg = "Unable to find type: " + typeName;
  115. throw(ParseException(msg));
  116. }
  117. return pType;
  118. }
  119. bool SchemaItem::addUniqueName(const std::string keyName)
  120. {
  121. auto result = m_keys.insert(keyName);
  122. return result.second; // true if keyName did not already exist
  123. }
  124. void SchemaItem::addSchemaType(const std::shared_ptr<SchemaItem> &pItem, const std::string &typeName)
  125. {
  126. auto it = m_schemaTypes.find(typeName);
  127. if (it == m_schemaTypes.end())
  128. {
  129. m_schemaTypes[typeName] = pItem;
  130. }
  131. else
  132. {
  133. throw(ParseException("Element: " + getProperty("name") + ", duplicate schema complex type found: " + typeName));
  134. }
  135. }
  136. std::shared_ptr<SchemaItem> SchemaItem::getSchemaType(const std::string &name, bool throwIfNotPresent) const
  137. {
  138. std::shared_ptr<SchemaItem> pItem;
  139. auto it = m_schemaTypes.find(name);
  140. if (it != m_schemaTypes.end())
  141. {
  142. return it->second;
  143. }
  144. else
  145. {
  146. std::shared_ptr<SchemaItem> pParent = m_pParent.lock();
  147. if (pParent)
  148. {
  149. return pParent->getSchemaType(name, throwIfNotPresent);
  150. }
  151. }
  152. //
  153. // Did not find the type
  154. if (throwIfNotPresent)
  155. {
  156. std::string msg = "Unable to find config type: " + name;
  157. throw(ParseException(msg));
  158. }
  159. return pItem;
  160. }
  161. //
  162. // This method is used to insert a named type into the current schema item. This is done by making copies
  163. // of the relevant members and inserting them into this instance
  164. void SchemaItem::insertSchemaType(const std::shared_ptr<SchemaItem> pTypeItem)
  165. {
  166. //
  167. // Attributes
  168. std::vector< std::shared_ptr<SchemaValue>> typeAttributes;
  169. pTypeItem->getAttributes(typeAttributes);
  170. for (auto attrIt = typeAttributes.begin(); attrIt != typeAttributes.end(); ++attrIt)
  171. {
  172. std::shared_ptr<SchemaValue> pNewAttr = std::make_shared<SchemaValue>(*(*attrIt));
  173. addAttribute(pNewAttr);
  174. }
  175. //
  176. // Type main value
  177. if (pTypeItem->getItemSchemaValue() != nullptr)
  178. {
  179. std::shared_ptr<SchemaValue> pNewItemCfgValue = std::make_shared<SchemaValue>(*(pTypeItem->getItemSchemaValue()));
  180. setItemSchemaValue(pNewItemCfgValue);
  181. }
  182. //
  183. // Unique attribute sets
  184. for (auto setIt = pTypeItem->m_uniqueAttributeValueSetDefs.begin(); setIt != pTypeItem->m_uniqueAttributeValueSetDefs.end(); ++setIt)
  185. {
  186. m_uniqueAttributeValueSetDefs.insert({ setIt->first, setIt->second });
  187. }
  188. //
  189. // Unique attribute reference sets
  190. for (auto it = pTypeItem->m_uniqueAttributeValueSetReferences.begin(); it != pTypeItem->m_uniqueAttributeValueSetReferences.end(); ++it)
  191. {
  192. m_uniqueAttributeValueSetReferences.insert({ it->first, it->second });
  193. }
  194. //
  195. // Children - note that making a copy will also create copies of all descendants
  196. std::vector<std::shared_ptr<SchemaItem>> typeChildren;
  197. pTypeItem->getChildren(typeChildren);
  198. for (auto childIt = typeChildren.begin(); childIt != typeChildren.end(); ++childIt)
  199. {
  200. std::shared_ptr<SchemaItem> pNewItem = std::make_shared<SchemaItem>(*(*childIt));
  201. pNewItem->setParentForChildren(shared_from_this());
  202. addChild(pNewItem);
  203. }
  204. }
  205. void SchemaItem::setParentForChildren(std::shared_ptr<SchemaItem> pParent)
  206. {
  207. setParent(pParent);
  208. for (auto &childIt: m_children)
  209. {
  210. childIt->setParentForChildren(shared_from_this());
  211. }
  212. }
  213. void SchemaItem::addAttribute(const std::shared_ptr<SchemaValue> &pCfgValue)
  214. {
  215. pCfgValue->setOrdinal(m_attributes.size());
  216. auto retVal = m_attributes.insert({ pCfgValue->getName(), pCfgValue });
  217. if (!retVal.second)
  218. {
  219. throw(ParseException("Element: " + getProperty("name") + ", duplicate attribute (" + pCfgValue->getName() + ") found"));
  220. }
  221. }
  222. void SchemaItem::addAttribute(const std::map<std::string, std::shared_ptr<SchemaValue>> &attributes)
  223. {
  224. for (auto it = attributes.begin(); it != attributes.end(); ++it)
  225. addAttribute(it->second);
  226. }
  227. void SchemaItem::addAttribute(const std::vector<std::shared_ptr<SchemaValue>> &attributes)
  228. {
  229. for (auto it=attributes.begin(); it!=attributes.end(); ++it)
  230. addAttribute(*it);
  231. }
  232. void SchemaItem::getAttributes(std::vector<std::shared_ptr<SchemaValue>> &attributes) const
  233. {
  234. for (auto it = m_attributes.begin(); it != m_attributes.end(); ++it)
  235. attributes.push_back(it->second);
  236. }
  237. std::shared_ptr<SchemaValue> SchemaItem::getAttribute(const std::string &name, bool createIfDoesNotExist) const
  238. {
  239. std::shared_ptr<SchemaValue> pCfgValue;
  240. auto it = m_attributes.find(name);
  241. if (it != m_attributes.end())
  242. {
  243. pCfgValue = it->second;
  244. }
  245. else if (createIfDoesNotExist)
  246. {
  247. // not found, build a default cfg value for the undefined attribute
  248. pCfgValue = std::make_shared<SchemaValue>(name, false);
  249. pCfgValue->setType(getSchemaValueType("default"));
  250. }
  251. return pCfgValue;
  252. }
  253. void SchemaItem::addUniqueAttributeValueSetDefinition(const std::string &setName, const std::string &elementPath, const std::string &attributeName, bool duplicateOk)
  254. {
  255. m_uniqueAttributeValueSetDefs.insert({ setName, SetInfo(setName, elementPath, attributeName, duplicateOk) }); // these are processed later
  256. }
  257. void SchemaItem::addReferenceToUniqueAttributeValueSet(const std::string &setName, const std::string &elementPath, const std::string &attributeName)
  258. {
  259. m_uniqueAttributeValueSetReferences.insert({ setName, SetInfo(setName, elementPath, attributeName) }); // these are processed later
  260. }
  261. void SchemaItem::addUniqueAttrValueSetDefsAndRefs(const std::shared_ptr<SchemaItem> &pSourceSchemaItem)
  262. {
  263. for (auto &ref: pSourceSchemaItem->m_uniqueAttributeValueSetReferences)
  264. {
  265. addReferenceToUniqueAttributeValueSet(ref.first, ref.second.m_elementPath, ref.second.m_attributeName);
  266. }
  267. for (auto &def: pSourceSchemaItem->m_uniqueAttributeValueSetDefs)
  268. {
  269. addUniqueAttributeValueSetDefinition(def.first, def.second.m_elementPath, def.second.m_attributeName, true);
  270. }
  271. }
  272. void SchemaItem::processUniqueAttributeValueSetReferences(const std::map<std::string, std::vector<std::shared_ptr<SchemaValue>>> &uniqueAttributeValueSets)
  273. {
  274. for (auto setRefIt = m_uniqueAttributeValueSetReferences.begin(); setRefIt != m_uniqueAttributeValueSetReferences.end(); ++setRefIt)
  275. {
  276. auto keyIt = uniqueAttributeValueSets.find(setRefIt->second.m_setName);
  277. if (keyIt != uniqueAttributeValueSets.end())
  278. {
  279. for (auto cfgIt = keyIt->second.begin(); cfgIt != keyIt->second.end(); ++cfgIt)
  280. {
  281. std::shared_ptr<SchemaValue> pKeyRefAttribute = *cfgIt; // this is the reference attribute from which attributeName must be a member
  282. std::string cfgValuePath = setRefIt->second.m_elementPath + "[@" + setRefIt->second.m_attributeName + "]";
  283. std::vector<std::shared_ptr<SchemaValue>> cfgValues;
  284. fetchSchemaValues(cfgValuePath, cfgValues);
  285. if (!cfgValues.empty())
  286. {
  287. for (auto attrIt = cfgValues.begin(); attrIt != cfgValues.end(); ++attrIt)
  288. {
  289. (*attrIt)->setUniqueValueSetRef(pKeyRefAttribute);
  290. }
  291. }
  292. else
  293. {
  294. throw(ParseException("Element: " + getProperty("name") + ", Attribute '" + (setRefIt->second.m_attributeName + "' not found when adding keyRef for key " + (setRefIt->second.m_setName))));
  295. }
  296. }
  297. }
  298. else
  299. {
  300. throw(ParseException("Element: " + getProperty("name") + ", Keyref to key '" + (setRefIt->second.m_setName + "' was not found")));
  301. }
  302. }
  303. }
  304. void SchemaItem::getChildren(std::vector<std::shared_ptr<SchemaItem>> &children, const std::string &name, const std::string &itemType) const
  305. {
  306. for (auto &pChild: m_children)
  307. {
  308. if (name.empty() || pChild->getProperty("name") == name)
  309. {
  310. if (itemType.empty() || pChild->getProperty("itemType") == itemType)
  311. {
  312. children.emplace_back(pChild);
  313. }
  314. }
  315. }
  316. }
  317. void SchemaItem::resetEnvironment()
  318. {
  319. for (auto it = m_attributes.begin(); it != m_attributes.end(); ++it)
  320. {
  321. it->second->resetEnvironment();
  322. }
  323. }
  324. void SchemaItem::fetchSchemaValues(const std::string &path, std::vector<std::shared_ptr<SchemaValue>> &schemaValues)
  325. {
  326. ConfigPath configPath(path);
  327. doFetchSchemaValues(configPath, schemaValues);
  328. }
  329. void SchemaItem::doFetchSchemaValues(ConfigPath &configPath, std::vector<std::shared_ptr<SchemaValue>> &schemaValues)
  330. {
  331. std::shared_ptr<ConfigPathItem> pPathItem = configPath.getNextPathItem();
  332. if (pPathItem)
  333. {
  334. if (pPathItem->isRoot())
  335. {
  336. getSchemaRoot()->doFetchSchemaValues(configPath, schemaValues);
  337. }
  338. else if (pPathItem->isParentPathtItem())
  339. {
  340. if (!m_pParent.expired())
  341. {
  342. m_pParent.lock()->doFetchSchemaValues(configPath, schemaValues);
  343. }
  344. }
  345. else if (pPathItem->isCurrentPathItem())
  346. {
  347. doFetchSchemaValues(configPath, schemaValues);
  348. }
  349. else
  350. {
  351. //
  352. // Get the items to check for this path element. If there is no element name, then use
  353. // this item, otherwise get children matching the element name
  354. std::vector<std::shared_ptr<SchemaItem>> items;
  355. if (pPathItem->getElementName().empty())
  356. {
  357. items.push_back(std::const_pointer_cast<SchemaItem>(shared_from_this()));
  358. }
  359. else
  360. {
  361. getChildren(items, pPathItem->getElementName());
  362. }
  363. if (!pPathItem->getAttributeName().empty()) // note that attribute values are not supported for schema xpaths
  364. {
  365. auto it = items.begin();
  366. while (it != items.end())
  367. {
  368. std::shared_ptr<SchemaValue> pAttribute = (*it)->getAttribute(pPathItem->getAttributeName());
  369. if (!pAttribute)
  370. {
  371. it = items.erase(it);
  372. }
  373. else
  374. {
  375. ++it;
  376. }
  377. }
  378. }
  379. //
  380. // If path elements remain, fetch schema values from each match at this level, otherwise push the results to
  381. // the result schema value vector
  382. if (configPath.isPathRemaining())
  383. {
  384. //
  385. // For all the matching nodes at this element, call each to continue the search
  386. for (auto itemIt = items.begin(); itemIt != items.end(); ++itemIt)
  387. {
  388. (*itemIt)->doFetchSchemaValues(configPath, schemaValues);
  389. }
  390. }
  391. else
  392. {
  393. for (auto itemIt = items.begin(); itemIt != items.end(); ++itemIt)
  394. {
  395. schemaValues.push_back((*itemIt)->getAttribute(pPathItem->getAttributeName()));
  396. }
  397. }
  398. }
  399. }
  400. }
  401. std::shared_ptr<SchemaItem> SchemaItem::getSchemaRoot()
  402. {
  403. if (!m_pParent.expired())
  404. {
  405. return m_pParent.lock()->getSchemaRoot();
  406. }
  407. std::shared_ptr<SchemaItem> ptr = shared_from_this();
  408. return ptr;
  409. }
  410. void SchemaItem::getPath(std::string &path) const
  411. {
  412. path = getProperty("name") + path;
  413. path = "/" + path;
  414. if (!m_pParent.expired())
  415. {
  416. m_pParent.lock()->getPath(path);
  417. }
  418. }
  419. void SchemaItem::processDefinedUniqueAttributeValueSets(std::map<std::string, std::vector<std::shared_ptr<SchemaValue>>> &uniqueAttributeValueSets)
  420. {
  421. for (auto setIt = m_uniqueAttributeValueSetDefs.begin(); setIt != m_uniqueAttributeValueSetDefs.end(); ++setIt)
  422. {
  423. auto it = uniqueAttributeValueSets.find(setIt->first);
  424. bool keyDefExists = it != uniqueAttributeValueSets.end();
  425. if (!keyDefExists || setIt->second.m_duplicateOk)
  426. {
  427. std::string cfgValuePath = setIt->second.m_elementPath + "[@" + setIt->second.m_attributeName + "]";
  428. std::vector<std::shared_ptr<SchemaValue>> cfgValues;
  429. fetchSchemaValues(cfgValuePath, cfgValues);
  430. if (!cfgValues.empty())
  431. {
  432. //
  433. // For each attribute, if it does not already exist in the list of attributes making up this
  434. // key value, add it.
  435. for (auto attrIt = cfgValues.begin(); attrIt != cfgValues.end(); ++attrIt)
  436. {
  437. (*attrIt)->setUniqueValue(true);
  438. if (!keyDefExists)
  439. {
  440. std::vector<std::shared_ptr<SchemaValue>> values;
  441. values.push_back(*attrIt);
  442. it = uniqueAttributeValueSets.insert({ setIt->second.m_setName, values }).first; // so the else condition will work
  443. keyDefExists = true; // Now, it does exist
  444. }
  445. else
  446. {
  447. std::vector<std::shared_ptr<SchemaValue>> &values = it->second;
  448. bool found = false;
  449. for (auto cfgIt = values.begin(); cfgIt != values.end() && !found; ++cfgIt)
  450. {
  451. found = (*cfgIt) == (*attrIt);
  452. }
  453. if (!found)
  454. values.push_back(*attrIt);
  455. }
  456. }
  457. }
  458. else
  459. {
  460. throw(ParseException("Element: " + getProperty("name", "unknown") + ", attribute " + setIt->second.m_attributeName + " not found for key " + setIt->second.m_setName));
  461. }
  462. }
  463. else
  464. {
  465. throw(ParseException("Element: " + getProperty("name", "unknown") + ", duplicate key (" + setIt->second.m_setName + ") found for element " + m_properties["name"]));
  466. }
  467. }
  468. //
  469. // Post process all of our children now
  470. for (auto &pChild: m_children)
  471. {
  472. pChild->processDefinedUniqueAttributeValueSets(uniqueAttributeValueSets);
  473. }
  474. }
  475. void SchemaItem::postProcessConfig(const std::map<std::string, std::vector<std::shared_ptr<SchemaValue>>> &uniqueAttributeValueSets)
  476. {
  477. //
  478. // Make sure that the item type value for all children that are insertable (minRequired = 0 or maxAllowed > minRequired)
  479. std::set<std::string> itemTypes;
  480. for (auto &pChild: m_children)
  481. {
  482. if (pChild->isInsertable())
  483. {
  484. auto rc = itemTypes.insert(pChild->getItemType());
  485. if (!rc.second)
  486. {
  487. throw(ParseException("Element: " + getProperty("name") + ", duplicate itemType(" + pChild->getItemType() + ") found"));
  488. }
  489. }
  490. }
  491. processUniqueAttributeValueSetReferences(uniqueAttributeValueSets);
  492. //
  493. // Post process the attributes
  494. for (auto it = m_attributes.begin(); it != m_attributes.end(); ++it)
  495. {
  496. //
  497. // If this is a mirroed value, go find the source and attach ourselves so that if that value changes,
  498. // it is replicated to us.
  499. if (it->second->isMirroredValue())
  500. {
  501. std::vector<std::shared_ptr<SchemaValue>> cfgValues;
  502. fetchSchemaValues(it->second->getMirrorFromPath(), cfgValues);
  503. if (!cfgValues.empty() && cfgValues.size() == 1)
  504. {
  505. if (cfgValues.size() == 1)
  506. {
  507. it->second->addMirroredSchemaValue(cfgValues[0]);
  508. }
  509. else
  510. {
  511. throw(ParseException("Element: " + getProperty("name") + ", multiple sources found for mirror from path for attribute " + it->second->getName() + " (path=" + it->second->getMirrorFromPath()));
  512. }
  513. }
  514. else
  515. {
  516. throw(ParseException("Element: " + getProperty("name") + ", mirrored from source not found for attribute '" + it->second->getName() + "' path=" + it->second->getMirrorFromPath()));
  517. }
  518. }
  519. }
  520. //
  521. // Post process all of our children now
  522. for (auto &pChild: m_children)
  523. {
  524. pChild->postProcessConfig(uniqueAttributeValueSets);
  525. }
  526. }
  527. std::string SchemaItem::getItemType() const
  528. {
  529. //
  530. // Return itemType based on this set of rules
  531. if (!getProperty("itemType").empty())
  532. return getProperty("itemType");
  533. return getProperty("name");
  534. }
  535. std::string SchemaItem::getProperty(const std::string &name, const std::string &dflt) const
  536. {
  537. std::string retVal = dflt;
  538. auto it = m_properties.find(name);
  539. if (it != m_properties.end())
  540. {
  541. retVal = it->second;
  542. }
  543. return retVal;
  544. }
  545. void SchemaItem::processEvent(const std::string &eventType, const std::shared_ptr<EnvironmentNode> &pEventSourceNode) const
  546. {
  547. //
  548. // Loop through any event handlers we may have
  549. for (auto eventIt = m_eventHandlers.begin(); eventIt != m_eventHandlers.end(); ++eventIt)
  550. {
  551. (*eventIt)->processEvent(eventType, pEventSourceNode);
  552. }
  553. //
  554. // Pass the event on because events are broadcast
  555. std::vector<std::shared_ptr<SchemaItem>> children;
  556. getChildren(children);
  557. for (auto childIt = children.begin(); childIt != children.end(); ++childIt)
  558. {
  559. (*childIt)->processEvent(eventType, pEventSourceNode);
  560. }
  561. }
  562. void SchemaItem::setRequiredInstanceComponents(const std::string list)
  563. {
  564. m_requiredInstanceComponents = splitString(list, "|");
  565. }
  566. void SchemaItem::validate(Status &status, bool includeChildren, bool includeHiddenNodes) const
  567. {
  568. //
  569. // If the schema is not hiding the node or we want hidden nodes, validate it
  570. if (!isHidden() || includeHiddenNodes)
  571. {
  572. //
  573. // Check the number of environment nodes against the allowed min/max range. Note that since the schema does not
  574. // maintain a parent child relationship like the environment, the environment nodes for this schema item need to
  575. // be separated by each environment node's parent. Then the number of nodes, by parent, is compared agains the
  576. // allowed min/max range
  577. std::map<std::string, std::vector<std::shared_ptr<EnvironmentNode>>> envNodesByParent;
  578. //
  579. // Fill in the nodes by parent so that we know how many of this schema item are under each parent. Note some will
  580. // be 0 and this needs to be known in case the min number is not 0. If there is not parent for this item, then we
  581. // are at the root and no check is necessary (expired check OK since the schema is static once loaded)
  582. if (!m_pParent.expired())
  583. {
  584. auto pParentItem = m_pParent.lock(); // also, schema items are not deleted, so this will always be good
  585. for (auto &pParentWeakEnvNode: pParentItem->m_envNodes)
  586. {
  587. std::shared_ptr<EnvironmentNode> pParentEnvNode = pParentWeakEnvNode.lock();
  588. if (pParentEnvNode)
  589. {
  590. envNodesByParent[pParentEnvNode->getId()] = std::vector<std::shared_ptr<EnvironmentNode>>();
  591. }
  592. }
  593. }
  594. //
  595. // Now build the vector per parent node ID
  596. for (auto &pWeakEnvNode: m_envNodes)
  597. {
  598. std::shared_ptr<EnvironmentNode> pEnvNode = pWeakEnvNode.lock();
  599. if (pEnvNode)
  600. {
  601. std::shared_ptr<EnvironmentNode> pParentEnvNode = pEnvNode->getParent();
  602. if (pParentEnvNode)
  603. {
  604. envNodesByParent[pParentEnvNode->getId()].emplace_back(pEnvNode);
  605. }
  606. }
  607. }
  608. //
  609. // Now validate the count of nodes
  610. for (auto &envNodes: envNodesByParent)
  611. {
  612. if (envNodes.second.size() < m_minInstances || envNodes.second.size() > m_maxInstances)
  613. {
  614. std::string path;
  615. getPath(path);
  616. std::string msg;
  617. msg = "The number of " + path + " nodes (" + std::to_string(envNodes.second.size()) +
  618. ") is outside the range of " + std::to_string(m_minInstances) +
  619. " to " + std::to_string(m_maxInstances);
  620. std::string nodeId = !envNodes.second.empty() ? envNodes.second[0]->getId() : "";
  621. status.addMsg(statusMsg::error, nodeId, "", msg);
  622. }
  623. }
  624. //
  625. // Now validate each environment node (at this time go ahead and reset the member variable of weak pointers as well
  626. // to get rid of any stale values)
  627. for (auto &pWeakEnvNode: m_envNodes)
  628. {
  629. std::shared_ptr<EnvironmentNode> pEnvNode = pWeakEnvNode.lock();
  630. if (pEnvNode)
  631. {
  632. pEnvNode->validate(status);
  633. }
  634. }
  635. //
  636. // Validate children, if so indicated
  637. if (includeChildren)
  638. {
  639. for (auto &pSchemaChild: m_children)
  640. {
  641. pSchemaChild->validate(status, includeChildren, includeHiddenNodes);
  642. }
  643. }
  644. }
  645. }